SkillAgentSearch skills...

Libhv

🔥 比libevent/libuv/asio更易用的网络库。A c/c++ network library for developing TCP/UDP/SSL/HTTP/WebSocket/MQTT client/server.

Install / Use

/learn @ithewei/Libhv

README

English | 中文

libhv

Linux Windows macOS Android iOS benchmark <br> release stars forks issues PRs contributors license <br> gitee awesome-c awesome-cpp

Like libevent, libev, and libuv, libhv provides event-loop with non-blocking IO and timer, but simpler api and richer protocols.

✨ Features

  • Cross-platform (Linux, Windows, macOS, Android, iOS, BSD, Solaris)
  • High-performance EventLoop (IO, timer, idle, custom, signal)
  • TCP/UDP client/server/proxy
  • TCP supports heartbeat, reconnect, upstream, MultiThread-safe write and close, etc.
  • Built-in common unpacking modes (FixedLength, Delimiter, LengthField)
  • RUDP support: WITH_KCP
  • SSL/TLS support: (via WITH_OPENSSL or WITH_GNUTLS or WITH_MBEDTLS)
  • HTTP client/server (support https http1/x http2 grpc)
  • HTTP supports static service, indexof service, forward/reverse proxy service, sync/async API handler
  • HTTP supports RESTful, router, middleware, keep-alive, chunked, SSE, etc.
  • WebSocket client/server
  • MQTT client

⌛️ Build

see BUILD.md

Makefile:

./configure
make
sudo make install

or cmake:

mkdir build
cd build
cmake ..
cmake --build .

or bazel:

bazel build libhv

or vcpkg:

vcpkg install libhv

or xmake:

xrepo install libhv

⚡️ Getting Started

run ./getting_started.sh:

git clone https://github.com/ithewei/libhv.git
cd libhv
./configure
make

bin/httpd -h
bin/httpd -d
#bin/httpd -c etc/httpd.conf -s restart -d
ps aux | grep httpd

# http file service
bin/curl -v localhost:8080

# http indexof service
bin/curl -v localhost:8080/downloads/

# http api service
bin/curl -v localhost:8080/ping
bin/curl -v localhost:8080/echo -d "hello,world!"
bin/curl -v localhost:8080/query?page_no=1\&page_size=10
bin/curl -v localhost:8080/kv   -H "Content-Type:application/x-www-form-urlencoded" -d 'user=admin&pswd=123456'
bin/curl -v localhost:8080/json -H "Content-Type:application/json" -d '{"user":"admin","pswd":"123456"}'
bin/curl -v localhost:8080/form -F 'user=admin' -F 'pswd=123456'
bin/curl -v localhost:8080/upload -d "@LICENSE"
bin/curl -v localhost:8080/upload -F "file=@LICENSE"

bin/curl -v localhost:8080/test -H "Content-Type:application/x-www-form-urlencoded" -d 'bool=1&int=123&float=3.14&string=hello'
bin/curl -v localhost:8080/test -H "Content-Type:application/json" -d '{"bool":true,"int":123,"float":3.14,"string":"hello"}'
bin/curl -v localhost:8080/test -F 'bool=1' -F 'int=123' -F 'float=3.14' -F 'string=hello'
# RESTful API: /group/:group_name/user/:user_id
bin/curl -v -X DELETE localhost:8080/group/test/user/123

# benchmark
bin/wrk -c 1000 -d 10 -t 4 http://127.0.0.1:8080/

TCP

tcp server

c version: examples/tcp_echo_server.c

c++ version: evpp/TcpServer_test.cpp

#include "TcpServer.h"
using namespace hv;

int main() {
    int port = 1234;
    TcpServer srv;
    int listenfd = srv.createsocket(port);
    if (listenfd < 0) {
        return -1;
    }
    printf("server listen on port %d, listenfd=%d ...\n", port, listenfd);
    srv.onConnection = [](const SocketChannelPtr& channel) {
        std::string peeraddr = channel->peeraddr();
        if (channel->isConnected()) {
            printf("%s connected! connfd=%d\n", peeraddr.c_str(), channel->fd());
        } else {
            printf("%s disconnected! connfd=%d\n", peeraddr.c_str(), channel->fd());
        }
    };
    srv.onMessage = [](const SocketChannelPtr& channel, Buffer* buf) {
        // echo
        channel->write(buf);
    };
    srv.setThreadNum(4);
    srv.start();

    // press Enter to stop
    while (getchar() != '\n');
    return 0;
}

tcp client

c version: examples/tcp_client_test.c

c++ version: evpp/TcpClient_test.cpp

#include <iostream>
#include "TcpClient.h"
using namespace hv;

int main() {
    int port = 1234;
    TcpClient cli;
    int connfd = cli.createsocket(port);
    if (connfd < 0) {
        return -1;
    }
    cli.onConnection = [](const SocketChannelPtr& channel) {
        std::string peeraddr = channel->peeraddr();
        if (channel->isConnected()) {
            printf("connected to %s! connfd=%d\n", peeraddr.c_str(), channel->fd());
        } else {
            printf("disconnected to %s! connfd=%d\n", peeraddr.c_str(), channel->fd());
        }
    };
    cli.onMessage = [](const SocketChannelPtr& channel, Buffer* buf) {
        printf("< %.*s\n", (int)buf->size(), (char*)buf->data());
    };
    cli.start();

    std::string str;
    while (std::getline(std::cin, str)) {
        if (str == "close") {
            cli.closesocket();
        } else if (str == "start") {
            cli.start();
        } else if (str == "stop") {
            cli.stop();
            break;
        } else {
            if (!cli.isConnected()) break;
            cli.send(str);
        }
    }
    return 0;
}

HTTP

http server

see examples/http_server_test.cpp

golang gin style

#include "HttpServer.h"
using namespace hv;

int main() {
    HttpService router;
    router.GET("/ping", [](HttpRequest* req, HttpResponse* resp) {
        return resp->String("pong");
    });

    router.GET("/data", [](HttpRequest* req, HttpResponse* resp) {
        static char data[] = "0123456789";
        return resp->Data(data, 10);
    });

    router.GET("/paths", [&router](HttpRequest* req, HttpResponse* resp) {
        return resp->Json(router.Paths());
    });

    router.GET("/get", [](HttpRequest* req, HttpResponse* resp) {
        resp->json["origin"] = req->client_addr.ip;
        resp->json["url"] = req->url;
        resp->json["args"] = req->query_params;
        resp->json["headers"] = req->headers;
        return 200;
    });

    router.POST("/echo", [](const HttpContextPtr& ctx) {
        return ctx->send(ctx->body(), ctx->type());
    });

    HttpServer server(&router);
    server.setPort(8080);
    server.setThreadNum(4);
    server.run();
    return 0;
}

http client

see examples/http_client_test.cpp

python requests style

#include "requests.h"

int main() {
    auto resp = requests::get("http://www.example.com");
    if (resp == NULL) {
        printf("request failed!\n");
    } else {
        printf("%s\n", resp->body.c_str());
    }

    resp = requests::post("127.0.0.1:8080/echo", "hello,world!");
    if (resp == NULL) {
        printf("request failed!\n");
    } else {
        printf("%s\n", resp->body.c_str());
    }

    return 0;
}

WebSocket

WebSocket server

see examples/websocket_server_test.cpp

#include "WebSocketServer.h"
using namespace hv;

int main(int argc, char** argv) {
    WebSocketService ws;
    ws.onopen = [](const WebSocketChannelPtr& channel, const HttpRequestPtr& req) {
        printf("onopen: GET %s\n", req->Path().c_str());
    };
    ws.onmessage = [](const WebSocketChannelPtr& channel, const std::string& msg) {
        printf("onmessage: %.*s\n", (int)msg.size(), msg.data());
    };
    ws.onclose = [](const WebSocketChannelPtr& channel) {
        printf("onclose\n");
    };

    WebSocketServer server(&ws);
    server.setPort(9999);
    server.setThreadNum(4);
    server.run();
    return 0;
}

WebSocket client

see examples/websocket_client_test.cpp

#include "WebSocketClient.h"
using namespace hv;

int main(int argc, char** argv) {
    WebSocketClient ws;
    ws.onopen = []() {
        printf("onopen\n");
    };
    ws.onmessage = [](const std::string& msg) {
        printf("onmessage: %.*s\n", (int)msg.size(), msg.data());
    };
    ws.onclose = []() {
        printf("onclose\n");
    };

    // reconnect: 1,2,4,8,10,10,10...
    reconn_setting_t reconn;
    reconn_setting_init(&reconn);
    reconn.min_delay = 1000;
    reconn.max_delay = 10000;
    reconn.delay_polic

Related Skills

View on GitHub
GitHub Stars7.5k
CategoryDevelopment
Updated21h ago
Forks1.3k

Languages

C

Security Score

100/100

Audited on Mar 19, 2026

No findings