libuv网络库的TCP服务端与客户端

基于libuv实现tcp客户端和服务端(支持监听1000多个端口;打印客户端服务端socket;固定端口连接) 服务端:监听本地1000多个端口;收到连接既接受并打印数据和客户端服务端socket;github#include <stdio.h> #include <stdlib.h> #include "include/uv.h" #define DEFAULT_BACKLOG 1000 #define NUM 1000/*1013*/ uv_loop_t *lo... 阅读详情

本人一直在寻找一个跨平台的网络库,boost与ACE比较庞大,不考虑。对比了libevent,libev,libuv后,最终选择了libuv.可libuv文档少,例子也简单,对于tcp只有个echo-server的例子。网上也找过对其封装的例子,如下


libsourcey库,封装了许多库。对libuv的封装跟其他代码耦合比较紧,难为剥离 http://sourcey.com/libuv-cpp-wrappers/
C++11封装的,可惜VS10未完全支持C++11 https://github.com/larroy/uvpp
C++封装的  https://github.com/keepallsimple/uvpp

       本人想实现一个raw tcp server,支持上万链接数的,网上找到的都没合适我的,没办法只能参照各例子自己封装了

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /*************************************** 
  2. * @file     tcpsocket.h 
  3. * @brief    基于libuv封装的tcp服务器与客户端,使用log4z作日志工具 
  4. * @details 
  5. * @author   陈吉宏, wqvbjhc@gmail.com 
  6. * @date     2014-5-13 
  7. * @mod      2014-5-13  phata  修正服务器与客户端的错误.现服务器支持多客户端连接 
  8.                               修改客户端测试代码,支持并发多客户端测试 
  9. ****************************************/  
  10. #ifndef TCPSocket_H  
  11. #define TCPSocket_H  
  12. #include "uv.h"  
  13. #include <string>  
  14. #include <list>  
  15. #include <map>  
  16. #define BUFFERSIZE (1024*1024)  
  17.   
  18. namespace uv  
  19. {  
  20. typedef void (*newconnect)(int clientid);  
  21. typedef void (*server_recvcb)(int cliendid, const char* buf, int bufsize);  
  22. typedef void (*client_recvcb)(const char* buf, int bufsize, void* userdata);  
  23.   
  24. class TCPServer;  
  25. class clientdata  
  26. {  
  27. public:  
  28.     clientdata(int clientid):client_id(clientid),recvcb_(nullptr) {  
  29.         client_handle = (uv_tcp_t*)malloc(sizeof(*client_handle));  
  30.         client_handle->data = this;  
  31.         readbuffer = uv_buf_init((char*)malloc(BUFFERSIZE), BUFFERSIZE);  
  32.         writebuffer = uv_buf_init((char*)malloc(BUFFERSIZE), BUFFERSIZE);  
  33.     }  
  34.     virtual ~clientdata() {  
  35.         free(readbuffer.base);  
  36.         readbuffer.base = nullptr;  
  37.         readbuffer.len = 0;  
  38.   
  39.         free(writebuffer.base);  
  40.         writebuffer.base = nullptr;  
  41.         writebuffer.len = 0;  
  42.   
  43.         free(client_handle);  
  44.         client_handle = nullptr;  
  45.     }  
  46.     int client_id;//客户端id,惟一  
  47.     uv_tcp_t* client_handle;//客户端句柄  
  48.     TCPServer* tcp_server;//服务器句柄(保存是因为某些回调函数需要到)  
  49.     uv_buf_t readbuffer;//接受数据的buf  
  50.     uv_buf_t writebuffer;//写数据的buf  
  51.     uv_write_t write_req;  
  52.     server_recvcb recvcb_;//接收数据回调给用户的函数  
  53. };  
  54.   
  55.   
  56. class TCPServer  
  57. {  
  58. public:  
  59.     TCPServer(uv_loop_t* loop = uv_default_loop());  
  60.     virtual ~TCPServer();  
  61.     static void StartLog(const char* logpath = nullptr);//启动日志,必须启动才会生成日志  
  62. public:  
  63.     //基本函数  
  64.     bool Start(const char *ip, int port);//启动服务器,地址为IP4  
  65.     bool Start6(const char *ip, int port);//启动服务器,地址为IP6  
  66.     void close();  
  67.   
  68.     bool setNoDelay(bool enable);  
  69.     bool setKeepAlive(int enable, unsigned int delay);  
  70.   
  71.     const char* GetLastErrMsg() const {  
  72.         return errmsg_.c_str();  
  73.     };  
  74.   
  75.     virtual int  send(int clientid, const char* data, std::size_t len);  
  76.     virtual void setnewconnectcb(newconnect cb);  
  77.     virtual void setrecvcb(int clientid,server_recvcb cb);//设置接收回调函数,每个客户端各有一个  
  78. protected:  
  79.     int GetAvailaClientID()const;//获取可用的client id  
  80.     bool DeleteClient(int clientid);//删除链表中的客户端  
  81.     //静态回调函数  
  82.     static void AfterServerRecv(uv_stream_t *client, ssize_t nread, const uv_buf_t* buf);  
  83.     static void AfterSend(uv_write_t *req, int status);  
  84.     static void onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf);  
  85.     static void AfterServerClose(uv_handle_t *handle);  
  86.     static void AfterClientClose(uv_handle_t *handle);  
  87.     static void acceptConnection(uv_stream_t *server, int status);  
  88.   
  89. private:  
  90.     bool init();  
  91.     bool run(int status = UV_RUN_DEFAULT);  
  92.     bool bind(const char* ip, int port);  
  93.     bool bind6(const char* ip, int port);  
  94.     bool listen(int backlog = 1024);  
  95.   
  96.   
  97.     uv_tcp_t server_;//服务器链接  
  98.     std::map<int,clientdata*> clients_list_;//子客户端链接  
  99.     uv_mutex_t mutex_handle_;//保护clients_list_  
  100.     uv_loop_t *loop_;  
  101.     std::string errmsg_;  
  102.     newconnect newconcb_;  
  103.     bool isinit_;//是否已初始化,用于close函数中判断  
  104. };  
  105.   
  106.   
  107.   
  108. class TCPClient  
  109. {  
  110.     //直接调用connect/connect6会进行连接  
  111. public:  
  112.     TCPClient(uv_loop_t* loop = uv_default_loop());  
  113.     virtual ~TCPClient();  
  114.     static void StartLog(const char* logpath = nullptr);//启动日志,必须启动才会生成日志  
  115. public:  
  116.     //基本函数  
  117.     virtual bool connect(const char* ip, int port);//启动connect线程,循环等待直到connect完成  
  118.     virtual bool connect6(const char* ip, int port);//启动connect线程,循环等待直到connect完成  
  119.     virtual int  send(const char* data, std::size_t len);  
  120.     virtual void setrecvcb(client_recvcb cb, void* userdata);////设置接收回调函数,只有一个  
  121.     void close();  
  122.   
  123.     //是否启用Nagle算法  
  124.     bool setNoDelay(bool enable);  
  125.     bool setKeepAlive(int enable, unsigned int delay);  
  126.   
  127.     const char* GetLastErrMsg() const {  
  128.         return errmsg_.c_str();  
  129.     };  
  130. protected:  
  131.     //静态回调函数  
  132.     static void AfterConnect(uv_connect_t* handle, int status);  
  133.     static void AfterClientRecv(uv_stream_t *client, ssize_t nread, const uv_buf_t* buf);  
  134.     static void AfterSend(uv_write_t *req, int status);  
  135.     static void onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf);  
  136.     static void AfterClose(uv_handle_t *handle);  
  137.   
  138.     static void ConnectThread(void* arg);//真正的connect线程  
  139.     static void ConnectThread6(void* arg);//真正的connect线程  
  140.   
  141.     bool init();  
  142.     bool run(int status = UV_RUN_DEFAULT);  
  143. private:  
  144.     enum {  
  145.         CONNECT_TIMEOUT,  
  146.         CONNECT_FINISH,  
  147.         CONNECT_ERROR,  
  148.         CONNECT_DIS,  
  149.     };  
  150.     uv_tcp_t client_;//客户端连接  
  151.     uv_loop_t *loop_;  
  152.     uv_write_t write_req_;//写时请求  
  153.     uv_connect_t connect_req_;//连接时请求  
  154.     uv_thread_t connect_threadhanlde_;//线程句柄  
  155.     std::string errmsg_;//错误信息  
  156.     uv_buf_t readbuffer_;//接受数据的buf  
  157.     uv_buf_t writebuffer_;//写数据的buf  
  158.     uv_mutex_t write_mutex_handle_;//保护write,保存前一write完成才进行下一write  
  159.   
  160.     int connectstatus_;//连接状态  
  161.     client_recvcb recvcb_;//回调函数  
  162.     void* userdata_;//回调函数的用户数据  
  163.     std::string connectip_;//连接的服务器IP  
  164.     int connectport_;//连接的服务器端口号  
  165.     bool isinit_;//是否已初始化,用于close函数中判断  
  166. };  
  167.   
  168. }  
  169.   
  170.   
  171. #endif // TCPSocket_H  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include "tcpsocket.h"  
  2. #include "log4z.h"  
  3.   
  4. std::string GetUVError(int retcode)  
  5. {  
  6.     std::string err;  
  7.     err = uv_err_name(retcode);  
  8.     err +=":";  
  9.     err += uv_strerror(retcode);  
  10.     return std::move(err);  
  11. }  
  12.   
  13. namespace uv  
  14. {  
  15. /*****************************************TCP Server*************************************************************/  
  16. TCPServer::TCPServer(uv_loop_t* loop)  
  17.     :newconcb_(nullptr), isinit_(false)  
  18. {  
  19.     loop_ = loop;  
  20. }  
  21.   
  22.   
  23. TCPServer::~TCPServer()  
  24. {  
  25.     close();  
  26.     LOGI("tcp server exit.");  
  27. }  
  28.   
  29. //初始化与关闭--服务器与客户端一致  
  30. bool TCPServer::init()  
  31. {  
  32.     if (isinit_) {  
  33.         return true;  
  34.     }  
  35.   
  36.     if (!loop_) {  
  37.         errmsg_ = "loop is null on tcp init.";  
  38.         LOGE(errmsg_);  
  39.         return false;  
  40.     }  
  41.     int iret = uv_mutex_init(&mutex_handle_);  
  42.     if (iret) {  
  43.         errmsg_ = GetUVError(iret);  
  44.         LOGE(errmsg_);  
  45.         return false;  
  46.     }  
  47.     iret = uv_tcp_init(loop_,&server_);  
  48.     if (iret) {  
  49.         errmsg_ = GetUVError(iret);  
  50.         LOGE(errmsg_);  
  51.         return false;  
  52.     }  
  53.     isinit_ = true;  
  54.     server_.data = this;  
  55.     //iret = uv_tcp_keepalive(&server_, 1, 60);//调用此函数后后续函数会调用出错  
  56.     //if (iret) {  
  57.     //  errmsg_ = GetUVError(iret);  
  58.     //  return false;  
  59.     //}  
  60.     return true;  
  61. }  
  62.   
  63. void TCPServer::close()  
  64. {  
  65.     for (auto it = clients_list_.begin(); it!=clients_list_.end(); ++it) {  
  66.         auto data = it->second;  
  67.         uv_close((uv_handle_t*)data->client_handle,AfterClientClose);  
  68.     }  
  69.     clients_list_.clear();  
  70.   
  71.     LOGI("close server");  
  72.     if (isinit_) {  
  73.         uv_close((uv_handle_t*) &server_, AfterServerClose);  
  74.         LOGI("close server");  
  75.     }  
  76.     isinit_ = false;  
  77.     uv_mutex_destroy(&mutex_handle_);  
  78. }  
  79.   
  80. bool TCPServer::run(int status)  
  81. {  
  82.     LOGI("server runing.");  
  83.     int iret = uv_run(loop_,(uv_run_mode)status);  
  84.     if (iret) {  
  85.         errmsg_ = GetUVError(iret);  
  86.         LOGE(errmsg_);  
  87.         return false;  
  88.     }  
  89.     return true;  
  90. }  
  91. //属性设置--服务器与客户端一致  
  92. bool TCPServer::setNoDelay(bool enable)  
  93. {  
  94.     int iret = uv_tcp_nodelay(&server_, enable ? 1 : 0);  
  95.     if (iret) {  
  96.         errmsg_ = GetUVError(iret);  
  97.         LOGE(errmsg_);  
  98.         return false;  
  99.     }  
  100.     return true;  
  101. }  
  102.   
  103. bool TCPServer::setKeepAlive(int enable, unsigned int delay)  
  104. {  
  105.     int iret = uv_tcp_keepalive(&server_, enable , delay);  
  106.     if (iret) {  
  107.         errmsg_ = GetUVError(iret);  
  108.         LOGE(errmsg_);  
  109.         return false;  
  110.     }  
  111.     return true;  
  112. }  
  113.   
  114. //作为server时的函数  
  115. bool TCPServer::bind(const char* ip, int port)  
  116. {  
  117.     struct sockaddr_in bind_addr;  
  118.     int iret = uv_ip4_addr(ip, port, &bind_addr);  
  119.     if (iret) {  
  120.         errmsg_ = GetUVError(iret);  
  121.         LOGE(errmsg_);  
  122.         return false;  
  123.     }  
  124.     iret = uv_tcp_bind(&server_, (const struct sockaddr*)&bind_addr,0);  
  125.     if (iret) {  
  126.         errmsg_ = GetUVError(iret);  
  127.         LOGE(errmsg_);  
  128.         return false;  
  129.     }  
  130.     LOGI("server bind ip="<<ip<<", port="<<port);  
  131.     return true;  
  132. }  
  133.   
  134. bool TCPServer::bind6(const char* ip, int port)  
  135. {  
  136.     struct sockaddr_in6 bind_addr;  
  137.     int iret = uv_ip6_addr(ip, port, &bind_addr);  
  138.     if (iret) {  
  139.         errmsg_ = GetUVError(iret);  
  140.         LOGE(errmsg_);  
  141.         return false;  
  142.     }  
  143.     iret = uv_tcp_bind(&server_, (const struct sockaddr*)&bind_addr,0);  
  144.     if (iret) {  
  145.         errmsg_ = GetUVError(iret);  
  146.         LOGE(errmsg_);  
  147.         return false;  
  148.     }  
  149.     LOGI("server bind ip="<<ip<<", port="<<port);  
  150.     return true;  
  151. }  
  152.   
  153. bool TCPServer::listen(int backlog)  
  154. {  
  155.     int iret = uv_listen((uv_stream_t*) &server_, backlog, acceptConnection);  
  156.     if (iret) {  
  157.         errmsg_ = GetUVError(iret);  
  158.         LOGE(errmsg_);  
  159.         return false;  
  160.     }  
  161.     LOGI("server listen");  
  162.     return true;  
  163. }  
  164.   
  165. bool TCPServer::Start( const char *ip, int port )  
  166. {  
  167.     close();  
  168.     if (!init()) {  
  169.         return false;  
  170.     }  
  171.     if (!bind(ip,port)) {  
  172.         return false;  
  173.     }  
  174.     if (!listen(SOMAXCONN)) {  
  175.         return false;  
  176.     }  
  177.     if (!run()) {  
  178.         return false;  
  179.     }  
  180.     LOGI("start listen "<<ip<<": "<<port);  
  181.     return true;  
  182. }  
  183.   
  184. bool TCPServer::Start6( const char *ip, int port )  
  185. {  
  186.     close();  
  187.     if (!init()) {  
  188.         return false;  
  189.     }  
  190.     if (!bind6(ip,port)) {  
  191.         return false;  
  192.     }  
  193.     if (!listen(SOMAXCONN)) {  
  194.         return false;  
  195.     }  
  196.     if (!run()) {  
  197.         return false;  
  198.     }  
  199.     return true;  
  200. }  
  201.   
  202. //服务器发送函数  
  203. int TCPServer::send(int clientid, const char* data, std::size_t len)  
  204. {  
  205.     auto itfind = clients_list_.find(clientid);  
  206.     if (itfind == clients_list_.end()) {  
  207.         errmsg_ = "can't find cliendid ";  
  208.         errmsg_ += std::to_string((long long)clientid);  
  209.         LOGE(errmsg_);  
  210.         return -1;  
  211.     }  
  212.     //自己控制data的生命周期直到write结束  
  213.     if (itfind->second->writebuffer.len < len) {  
  214.         itfind->second->writebuffer.base = (char*)realloc(itfind->second->writebuffer.base,len);  
  215.         itfind->second->writebuffer.len = len;  
  216.     }  
  217.     memcpy(itfind->second->writebuffer.base,data,len);  
  218.     uv_buf_t buf = uv_buf_init((char*)itfind->second->writebuffer.base,len);  
  219.     int iret = uv_write(&itfind->second->write_req, (uv_stream_t*)itfind->second->client_handle, &buf, 1, AfterSend);  
  220.     if (iret) {  
  221.         errmsg_ = GetUVError(iret);  
  222.         LOGE(errmsg_);  
  223.         return false;  
  224.     }  
  225.     return true;  
  226. }  
  227.   
  228. //服务器-新客户端函数  
  229. void TCPServer::acceptConnection(uv_stream_t *server, int status)  
  230. {  
  231.     if (!server->data) {  
  232.         return;  
  233.     }  
  234.     TCPServer *tcpsock = (TCPServer *)server->data;  
  235.     int clientid = tcpsock->GetAvailaClientID();  
  236.     clientdata* cdata = new clientdata(clientid);//uv_close回调函数中释放  
  237.     cdata->tcp_server = tcpsock;//保存服务器的信息  
  238.     int iret = uv_tcp_init(tcpsock->loop_, cdata->client_handle);//析构函数释放  
  239.     if (iret) {  
  240.         delete cdata;  
  241.         tcpsock->errmsg_ = GetUVError(iret);  
  242.         LOGE(tcpsock->errmsg_);  
  243.         return;  
  244.     }  
  245.     iret = uv_accept((uv_stream_t*)&tcpsock->server_, (uv_stream_t*) cdata->client_handle);  
  246.     if ( iret) {  
  247.         tcpsock->errmsg_ = GetUVError(iret);  
  248.         uv_close((uv_handle_t*) cdata->client_handle, NULL);  
  249.         delete cdata;  
  250.         LOGE(tcpsock->errmsg_);  
  251.         return;  
  252.     }  
  253.     tcpsock->clients_list_.insert(std::make_pair(clientid,cdata));//加入到链接队列  
  254.     if (tcpsock->newconcb_) {  
  255.         tcpsock->newconcb_(clientid);  
  256.     }  
  257.     LOGI("new client("<<cdata->client_handle<<") id="<< clientid);  
  258.     iret = uv_read_start((uv_stream_t*)cdata->client_handle, onAllocBuffer, AfterServerRecv);//服务器开始接收客户端的数据  
  259.     return;  
  260. }  
  261.   
  262. //服务器-接收数据回调函数  
  263. void TCPServer::setrecvcb(int clientid, server_recvcb cb )  
  264. {  
  265.     auto itfind = clients_list_.find(clientid);  
  266.     if (itfind != clients_list_.end()) {  
  267.         itfind->second->recvcb_ = cb;  
  268.     }  
  269. }  
  270.   
  271. //服务器-新链接回调函数  
  272. void TCPServer::setnewconnectcb(newconnect cb )  
  273. {  
  274.     newconcb_ = cb;  
  275. }  
  276.   
  277. //服务器分析空间函数  
  278. void TCPServer::onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)  
  279. {  
  280.     if (!handle->data) {  
  281.         return;  
  282.     }  
  283.     clientdata *client = (clientdata*)handle->data;  
  284.     *buf = client->readbuffer;  
  285. }  
  286.   
  287. void TCPServer::AfterServerRecv(uv_stream_t *handle, ssize_t nread, const uv_buf_t* buf)  
  288. {  
  289.     if (!handle->data) {  
  290.         return;  
  291.     }  
  292.     clientdata *client = (clientdata*)handle->data;//服务器的recv带的是clientdata  
  293.     if (nread < 0) {/* Error or EOF */  
  294.         TCPServer *server = (TCPServer *)client->tcp_server;  
  295.         if (nread == UV_EOF) {  
  296.             fprintf(stdout,"客户端(%d)连接断开,关闭此客户端\n",client->client_id);  
  297.             LOGW("客户端("<<client->client_id<<")主动断开");  
  298.         } else if (nread == UV_ECONNRESET) {  
  299.             fprintf(stdout,"客户端(%d)异常断开\n",client->client_id);  
  300.             LOGW("客户端("<<client->client_id<<")异常断开");  
  301.         } else {  
  302.             fprintf(stdout,"%s\n",GetUVError(nread));  
  303.             LOGW("客户端("<<client->client_id<<")异常断开:"<<GetUVError(nread));  
  304.         }  
  305.         server->DeleteClient(client->client_id);//连接断开,关闭客户端  
  306.         return;  
  307.     } else if (0 == nread)  {/* Everything OK, but nothing read. */  
  308.   
  309.     } else if (client->recvcb_) {  
  310.         client->recvcb_(client->client_id,buf->base,nread);  
  311.     }  
  312. }  
  313.   
  314. //服务器与客户端一致  
  315. void TCPServer::AfterSend(uv_write_t *req, int status)  
  316. {  
  317.     if (status < 0) {  
  318.         LOGE("发送数据有误:"<<GetUVError(status));  
  319.         fprintf(stderr, "Write error %s\n", GetUVError(status));  
  320.     }  
  321. }  
  322.   
  323. void TCPServer::AfterServerClose(uv_handle_t *handle)  
  324. {  
  325.     //服务器,不需要做什么  
  326. }  
  327.   
  328. void TCPServer::AfterClientClose(uv_handle_t *handle)  
  329. {  
  330.     clientdata *cdata = (clientdata*)handle->data;  
  331.     LOGI("client "<<cdata->client_id<<" had closed.");  
  332.     delete cdata;  
  333. }  
  334.   
  335. int TCPServer::GetAvailaClientID() const  
  336. {  
  337.     static int s_id = 0;  
  338.     return ++s_id;  
  339. }  
  340.   
  341. bool TCPServer::DeleteClient( int clientid )  
  342. {  
  343.     uv_mutex_lock(&mutex_handle_);  
  344.     auto itfind = clients_list_.find(clientid);  
  345.     if (itfind == clients_list_.end()) {  
  346.         errmsg_ = "can't find client ";  
  347.         errmsg_ += std::to_string((long long)clientid);  
  348.         LOGE(errmsg_);  
  349.         uv_mutex_unlock(&mutex_handle_);  
  350.         return false;  
  351.     }  
  352.     if (uv_is_active((uv_handle_t*)itfind->second->client_handle)) {  
  353.         uv_read_stop((uv_stream_t*)itfind->second->client_handle);  
  354.     }  
  355.     uv_close((uv_handle_t*)itfind->second->client_handle,AfterClientClose);  
  356.   
  357.     clients_list_.erase(itfind);  
  358.     LOGI("删除客户端"<<clientid);  
  359.     uv_mutex_unlock(&mutex_handle_);  
  360.     return true;  
  361. }  
  362.   
  363.   
  364. void TCPServer::StartLog( const char* logpath /*= nullptr*/ )  
  365. {  
  366.     zsummer::log4z::ILog4zManager::GetInstance()->SetLoggerMonthdir(LOG4Z_MAIN_LOGGER_ID, true);  
  367.     zsummer::log4z::ILog4zManager::GetInstance()->SetLoggerDisplay(LOG4Z_MAIN_LOGGER_ID,false);  
  368.     zsummer::log4z::ILog4zManager::GetInstance()->SetLoggerLevel(LOG4Z_MAIN_LOGGER_ID,LOG_LEVEL_DEBUG);  
  369.     zsummer::log4z::ILog4zManager::GetInstance()->SetLoggerLimitSize(LOG4Z_MAIN_LOGGER_ID,100);  
  370.     if (logpath) {  
  371.         zsummer::log4z::ILog4zManager::GetInstance()->SetLoggerPath(LOG4Z_MAIN_LOGGER_ID,logpath);  
  372.     }  
  373.     zsummer::log4z::ILog4zManager::GetInstance()->Start();  
  374. }  
  375.   
  376.   
  377. /*****************************************TCP Client*************************************************************/  
  378. TCPClient::TCPClient(uv_loop_t* loop)  
  379.     :recvcb_(nullptr),userdata_(nullptr)  
  380.     ,connectstatus_(CONNECT_DIS)  
  381.     , isinit_(false)  
  382. {  
  383.     readbuffer_ = uv_buf_init((char*) malloc(BUFFERSIZE), BUFFERSIZE);  
  384.     writebuffer_ = uv_buf_init((char*) malloc(BUFFERSIZE), BUFFERSIZE);  
  385.     loop_ = loop;  
  386.     connect_req_.data = this;  
  387.     write_req_.data = this;  
  388. }  
  389.   
  390.   
  391. TCPClient::~TCPClient()  
  392. {  
  393.     free(readbuffer_.base);  
  394.     readbuffer_.base = nullptr;  
  395.     readbuffer_.len = 0;  
  396.     free(writebuffer_.base);  
  397.     writebuffer_.base = nullptr;  
  398.     writebuffer_.len = 0;  
  399.     close();  
  400.     LOGI("客户端("<<this<<")退出");  
  401. }  
  402. //初始化与关闭--服务器与客户端一致  
  403. bool TCPClient::init()  
  404. {  
  405.     if (isinit_) {  
  406.         return true;  
  407.     }  
  408.   
  409.     if (!loop_) {  
  410.         errmsg_ = "loop is null on tcp init.";  
  411.         LOGE(errmsg_);  
  412.         return false;  
  413.     }  
  414.     int iret = uv_tcp_init(loop_,&client_);  
  415.     if (iret) {  
  416.         errmsg_ = GetUVError(iret);  
  417.         LOGE(errmsg_);  
  418.         return false;  
  419.     }  
  420.     iret = uv_mutex_init(&write_mutex_handle_);  
  421.     if (iret) {  
  422.         errmsg_ = GetUVError(iret);  
  423.         LOGE(errmsg_);  
  424.         return false;  
  425.     }  
  426.     isinit_ = true;  
  427.     fprintf(stdout,"客户端(%p) init type = %d\n",&client_,client_.type);  
  428.     client_.data = this;  
  429.     //iret = uv_tcp_keepalive(&client_, 1, 60);//  
  430.     //if (iret) {  
  431.     //    errmsg_ = GetUVError(iret);  
  432.     //    return false;  
  433.     //}  
  434.     LOGI("客户端("<<this<<")Init");  
  435.     return true;  
  436. }  
  437.   
  438. void TCPClient::close()  
  439. {  
  440.     if (!isinit_) {  
  441.         return;  
  442.     }  
  443.     uv_mutex_destroy(&write_mutex_handle_);  
  444.     uv_close((uv_handle_t*) &client_, AfterClose);  
  445.     LOGI("客户端("<<this<<")close");  
  446.     isinit_ = false;  
  447. }  
  448.   
  449. bool TCPClient::run(int status)  
  450. {  
  451.     LOGI("客户端("<<this<<")run");  
  452.     int iret = uv_run(loop_,(uv_run_mode)status);  
  453.     if (iret) {  
  454.         errmsg_ = GetUVError(iret);  
  455.         LOGE(errmsg_);  
  456.         return false;  
  457.     }  
  458.     return true;  
  459. }  
  460.   
  461. //属性设置--服务器与客户端一致  
  462. bool TCPClient::setNoDelay(bool enable)  
  463. {  
  464.     //http://blog.youkuaiyun.com/u011133100/article/details/21485983  
  465.     int iret = uv_tcp_nodelay(&client_, enable ? 1 : 0);  
  466.     if (iret) {  
  467.         errmsg_ = GetUVError(iret);  
  468.         LOGE(errmsg_);  
  469.         return false;  
  470.     }  
  471.     return true;  
  472. }  
  473.   
  474. bool TCPClient::setKeepAlive(int enable, unsigned int delay)  
  475. {  
  476.     int iret = uv_tcp_keepalive(&client_, enable , delay);  
  477.     if (iret) {  
  478.         errmsg_ = GetUVError(iret);  
  479.         LOGE(errmsg_);  
  480.         return false;  
  481.     }  
  482.     return true;  
  483. }  
  484.   
  485. //作为client的connect函数  
  486. bool TCPClient::connect(const char* ip, int port)  
  487. {  
  488.     close();  
  489.     init();  
  490.     connectip_ = ip;  
  491.     connectport_ = port;  
  492.     LOGI("客户端("<<this<<")start connect to server("<<ip<<":"<<port<<")");  
  493.     int iret = uv_thread_create(&connect_threadhanlde_, ConnectThread, this);//触发AfterConnect才算真正连接成功,所以用线程  
  494.     if (iret) {  
  495.         errmsg_ = GetUVError(iret);  
  496.         LOGE(errmsg_);  
  497.         return false;  
  498.     }  
  499.     while ( connectstatus_ == CONNECT_DIS) {  
  500. #if defined (WIN32) || defined(_WIN32)  
  501.         Sleep(100);  
  502. #else  
  503.         usleep((100) * 1000)  
  504. #endif  
  505.     }  
  506.     return connectstatus_ == CONNECT_FINISH;  
  507. }  
  508.   
  509. bool TCPClient::connect6(const char* ip, int port)  
  510. {  
  511.     close();  
  512.     init();  
  513.     connectip_ = ip;  
  514.     connectport_ = port;  
  515.     LOGI("客户端("<<this<<")start connect to server("<<ip<<":"<<port<<")");  
  516.     int iret = uv_thread_create(&connect_threadhanlde_, ConnectThread6, this);//触发AfterConnect才算真正连接成功,所以用线程  
  517.     if (iret) {  
  518.         errmsg_ = GetUVError(iret);  
  519.         LOGE(errmsg_);  
  520.         return false;  
  521.     }  
  522.     while ( connectstatus_ == CONNECT_DIS) {  
  523.         //fprintf(stdout,"client(%p) wait, connect status %d\n",this,connectstatus_);  
  524. #if defined (WIN32) || defined(_WIN32)  
  525.         Sleep(100);  
  526. #else  
  527.         usleep((100) * 1000)  
  528. #endif  
  529.     }  
  530.     return connectstatus_ == CONNECT_FINISH;  
  531. }  
  532.   
  533. void TCPClient::ConnectThread( void* arg )  
  534. {  
  535.     TCPClient *pclient = (TCPClient*)arg;  
  536.     fprintf(stdout,"client(%p) ConnectThread start\n",pclient);  
  537.     struct sockaddr_in bind_addr;  
  538.     int iret = uv_ip4_addr(pclient->connectip_.c_str(), pclient->connectport_, &bind_addr);  
  539.     if (iret) {  
  540.         pclient->errmsg_ = GetUVError(iret);  
  541.         LOGE(pclient->errmsg_);  
  542.         return;  
  543.     }  
  544.     iret = uv_tcp_connect(&pclient->connect_req_, &pclient->client_, (const sockaddr*)&bind_addr, AfterConnect);  
  545.     if (iret) {  
  546.         pclient->errmsg_ = GetUVError(iret);  
  547.         LOGE(pclient->errmsg_);  
  548.         return;  
  549.     }  
  550.     fprintf(stdout,"client(%p) ConnectThread end, connect status %d\n",pclient, pclient->connectstatus_);  
  551.     pclient->run();  
  552. }  
  553.   
  554.   
  555. void TCPClient::ConnectThread6( void* arg )  
  556. {  
  557.     TCPClient *pclient = (TCPClient*)arg;  
  558.     LOGI("客户端("<<pclient<<")Enter Connect Thread.");  
  559.     fprintf(stdout,"client(%p) ConnectThread start\n",pclient);  
  560.     struct sockaddr_in6 bind_addr;  
  561.     int iret = uv_ip6_addr(pclient->connectip_.c_str(), pclient->connectport_, &bind_addr);  
  562.     if (iret) {  
  563.         pclient->errmsg_ = GetUVError(iret);  
  564.         LOGE(pclient->errmsg_);  
  565.         return;  
  566.     }  
  567.     iret = uv_tcp_connect(&pclient->connect_req_, &pclient->client_, (const sockaddr*)&bind_addr, AfterConnect);  
  568.     if (iret) {  
  569.         pclient->errmsg_ = GetUVError(iret);  
  570.         LOGE(pclient->errmsg_);  
  571.         return;  
  572.     }  
  573.     fprintf(stdout,"client(%p) ConnectThread end, connect status %d\n",pclient, pclient->connectstatus_);  
  574.     LOGI("客户端("<<pclient<<")Leave Connect Thread. connect status "<<pclient->connectstatus_);  
  575.     pclient->run();  
  576. }  
  577.   
  578. void TCPClient::AfterConnect(uv_connect_t* handle, int status)  
  579. {  
  580.     fprintf(stdout,"start after connect\n");  
  581.     TCPClient *pclient = (TCPClient*)handle->handle->data;  
  582.     if (status) {  
  583.         pclient->connectstatus_ = CONNECT_ERROR;  
  584.         fprintf(stdout,"connect error:%s\n",GetUVError(status));  
  585.         return;  
  586.     }  
  587.   
  588.     int iret = uv_read_start(handle->handle, onAllocBuffer, AfterClientRecv);//客户端开始接收服务器的数据  
  589.     if (iret) {  
  590.         fprintf(stdout,"uv_read_start error:%s\n",GetUVError(iret));  
  591.         pclient->connectstatus_ = CONNECT_ERROR;  
  592.     } else {  
  593.         pclient->connectstatus_ = CONNECT_FINISH;  
  594.     }  
  595.     LOGI("客户端("<<pclient<<")run");  
  596.     fprintf(stdout,"end after connect\n");  
  597. }  
  598.   
  599. //客户端的发送函数  
  600. int TCPClient::send(const char* data, std::size_t len)  
  601. {  
  602.     //自己控制data的生命周期直到write结束  
  603.     if (!data || len <= 0) {  
  604.         errmsg_ = "send data is null or len less than zero.";  
  605.         return 0;  
  606.     }  
  607.   
  608.     uv_mutex_lock(&write_mutex_handle_);  
  609.     if (writebuffer_.len < len) {  
  610.         writebuffer_.base = (char*)realloc(writebuffer_.base,len);  
  611.         writebuffer_.len = len;  
  612.     }  
  613.     memcpy(writebuffer_.base,data,len);  
  614.     uv_buf_t buf = uv_buf_init((char*)writebuffer_.base,len);  
  615.     int iret = uv_write(&write_req_, (uv_stream_t*)&client_, &buf, 1, AfterSend);  
  616.     if (iret) {  
  617.         uv_mutex_unlock(&write_mutex_handle_);  
  618.         errmsg_ = GetUVError(iret);  
  619.         LOGE(errmsg_);  
  620.         return false;  
  621.     }  
  622.     return true;  
  623. }  
  624.   
  625. //客户端-接收数据回调函数  
  626. void TCPClient::setrecvcb(client_recvcb cb, void* userdata )  
  627. {  
  628.     recvcb_ = cb;  
  629.     userdata_ = userdata;  
  630. }  
  631.   
  632. //客户端分析空间函数  
  633. void TCPClient::onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)  
  634. {  
  635.     if (!handle->data) {  
  636.         return;  
  637.     }  
  638.     TCPClient *client = (TCPClient*)handle->data;  
  639.     *buf = client->readbuffer_;  
  640. }  
  641.   
  642.   
  643. void TCPClient::AfterClientRecv(uv_stream_t *handle, ssize_t nread, const uv_buf_t* buf)  
  644. {  
  645.     if (!handle->data) {  
  646.         return;  
  647.     }  
  648.     TCPClient *client = (TCPClient*)handle->data;//服务器的recv带的是TCPClient  
  649.     if (nread < 0) {  
  650.         if (nread == UV_EOF) {  
  651.             fprintf(stdout,"服务器(%p)主动断开\n",handle);  
  652.             LOGW("服务器主动断开");  
  653.         } else if (nread == UV_ECONNRESET) {  
  654.             fprintf(stdout,"服务器(%p)异常断开\n",handle);  
  655.             LOGW("服务器异常断开");  
  656.         } else {  
  657.             fprintf(stdout,"服务器(%p)异常断开:%s\n",handle,GetUVError(nread));  
  658.             LOGW("服务器异常断开"<<GetUVError(nread));  
  659.         }  
  660.         uv_close((uv_handle_t*)handle, AfterClose);  
  661.         return;  
  662.     }  
  663.     if (nread > 0 && client->recvcb_) {  
  664.         client->recvcb_(buf->base,nread,client->userdata_);  
  665.     }  
  666. }  
  667.   
  668. //服务器与客户端一致  
  669. void TCPClient::AfterSend(uv_write_t *req, int status)  
  670. {  
  671.     TCPClient *client = (TCPClient *)req->handle->data;  
  672.     uv_mutex_unlock(&client->write_mutex_handle_);  
  673.     if (status < 0) {  
  674.         LOGE("发送数据有误:"<<GetUVError(status));  
  675.         fprintf(stderr, "Write error %s\n", GetUVError(status));  
  676.     }  
  677. }  
  678. //服务器与客户端一致  
  679. void TCPClient::AfterClose(uv_handle_t *handle)  
  680. {  
  681.     fprintf(stdout,"客户端(%p)已close\n",handle);  
  682.     LOGI("客户端("<<handle<<")已close");  
  683. }  
  684.   
  685. void TCPClient::StartLog( const char* logpath /*= nullptr*/ )  
  686. {  
  687.     zsummer::log4z::ILog4zManager::GetInstance()->SetLoggerMonthdir(LOG4Z_MAIN_LOGGER_ID, true);  
  688.     zsummer::log4z::ILog4zManager::GetInstance()->SetLoggerDisplay(LOG4Z_MAIN_LOGGER_ID,false);  
  689.     zsummer::log4z::ILog4zManager::GetInstance()->SetLoggerLevel(LOG4Z_MAIN_LOGGER_ID,LOG_LEVEL_DEBUG);  
  690.     zsummer::log4z::ILog4zManager::GetInstance()->SetLoggerLimitSize(LOG4Z_MAIN_LOGGER_ID,100);  
  691.     if (logpath) {  
  692.         zsummer::log4z::ILog4zManager::GetInstance()->SetLoggerPath(LOG4Z_MAIN_LOGGER_ID,logpath);  
  693.     }  
  694.     zsummer::log4z::ILog4zManager::GetInstance()->Start();  
  695. }  
  696.   
  697. }  

按照例子,客户端可以并发20多路,超过uv_write就会assert出错,未找到原因

服务器可以接收几十路连接。万百上千路未测试过,因为没有模拟环境。

C网络库使用(一):libuv的安装、多线程tcp客户端、多线程tcp服务器的使用 参考网址:https://github.com/libuv/libuv/blob/master/README.md https://www.cnblogs.com/cnxkey/articles/10058702.html 一、libuv的安装 1、windows下安装(这里使用vs2017进行编译) 下载libuv:https://github.com/libuv/libuv ... 阅读详情

相关推荐

C++高性能网络库Fastsocket:多Reactor模型与内存池优化实践

在C++服务端开发中,网络通信框架是构建高并发、低延迟应用的核心基础。其核心原理通常基于事件驱动模型,通过Reactor模式高效管理海量连接与IO事件,以最大化利用现代多核硬件性能。这类技术的核心价值在于,通过精巧的架构设计,在提供简洁开发接口的同时,实现极致的吞吐量与资源利用率,广泛应用于游戏服务器、实时通信、金融交易等对性能有严苛要求的场景。本文聚焦的Fastsocket网络库,正是这一理念的工程实践典范。它通过改良的多Reactor架构实现高效的连接与事件分发,并深度优化内存管理,采用对象池与内存池技

weixin_30703911的博客 377

Socket编程系列之6:Libuv高性能异步IO及高效网络编程

Socket编程系列初步计划:Socket编程系列之1:Linux-API网络编程入门实战Socket编程系列之2:Windows-API网络编程入门实战Socket编程系列之3:Libevent网络编程入门实战Socket编程系列之4:Libcurl网络编程入门实战Socket编程系列之5:Boost-ASIO网络编程入门实战Socket编程系列之6:Libuv网络编程入门实战----------------------------------------------------Socket编程系列之6:Libuv高性能异步IO及高效网络编程Libuv是一个高效的异步IO开发库,Linux下采取libev,Windows下独立编程实现IOCP高效网络编程。我将带领大家进行Libuv小白入门知识的讲解,并亲手配置环境,跑起来一个HelloWorld案例。然后进行各个方面的项目实战,并深入分析原理,包括:Libuv进程开发实战、网络开发实战、线程开发实战等。

LIBHV 实现TCP服务

最近的项目上,用到了LIBHV,特此预研了一下,接下来在项目上把它利用起来。 git clone https://github.com/ithewei/libhv.git cd libhv ./configure make 编译很简单,在ubuntu上很快就编译好啦。

xiaoning132的专栏 3230

基于libuv库实现tcpserver和tcpclient

项目中使用网络实现高速收发文件,经过验证,决定采用libuv库搭建tcpserver和tcpclient。libuv库是第三方库,其大量采用回调实现。同时,其官方关于server端以及client的demo都是十分简单,无法满足实际需求,因此在采用libuv的基础上,自行封装成类作为中间件,方便应用层调用。

qq_36731830的博客 2370

libuv关于TCP UDP以及文件操作的封装测试

libuv关于TCP UDP以及文件操作的封装测试,便于以后进行扩展使用

电商数据分析18——电商广告投放的数据分析与优化

在当今的电商行业中,广告投放是提高品牌知名度、吸引潜在客户和增加销售额的关键策略之一。随着市场竞争的加剧,仅仅依靠直观判断和传统方法已经无法满足广告投放的需求。数据分析在这里扮演了至关重要的角色,它可以帮助企业更准确地定位目标受众,评估广告效果,优化广告内容,从而提高广告效率和投资回报率(ROI)。

theskylife的博客 5701

libhv FAQ

Q:libhv名称由来 Q:libhv和libevent、libev、libuv有什么不同 Q:libhv的定位 Q:libhv的发展规划 Q:libhv性能如何 Q:libhv稳定性如何,是否商用 Q:libhv如何入门 Q:libhv如何使用 Q:libhv如何交叉编译 Q:libhv在Windows下如何编译 Q:Windows下编译不过 Q:Windows下链接不过 Q:如何开启SSL/TLS、https、wss功能 Q:Windows下如何集成openssl

HW的博客 7843

别再花钱买插件了!手把手教你实现UE5运行时动态导入FBX模型(附完整源码解析)

本文详细解析了UE5运行时动态导入FBX模型的全过程,从FBX SDK集成配置到核心解析流程,再到引擎资源转换和性能优化。通过多线程加载架构和内存优化技巧,开发者可以高效实现动态模型导入,避免购买昂贵插件。文章还提供了完整源码解析和高级功能扩展,帮助开发者深入理解UE5的底层资源管理机制。

weixin_27033895的博客 377

使用 libuv 实现高性能 C++ TCP 服务器(支持粘包拆包处理)【附完整代码】

本文介绍了如何使用 libuv 实现一个支持粘包拆包处理的 C++ TCP 服务器。首先讲解了 TCP 粘包/拆包问题的原理及其原因,随后通过“定长包头 + 不定长消息体”的协议方式解决消息边界问题。文章详细展示了基于 libuv 的服务端代码实现,包括连接处理、数据接收与缓冲区解析逻辑,并提供 Python 客户端进行测试验证。适合有一定 C++ 基础的开发者参考,适用于高并发、跨平台网络编程场景。

hengdela的博客 1025

PCB工程师必看:别再搞错1078玻纤布的Dk了,手把手教你算等效介电常数

本文为PCB工程师提供了1078玻纤布等效介电常数(Dk)的详细计算指南,帮助解决高速设计中的信号完整性问题。通过解析玻纤布结构、混合介质理论和实战计算方法,指导工程师准确设置EDA工具参数,避免常见的Dk计算误区,提升设计精度和仿真准确性。

weixin_42546392的博客 398

避坑指南:ros2_control在Gazebo中的常见配置错误及解决方案

本文系统梳理了在Gazebo仿真环境中配置ros2_control框架时最常见的错误,并提供了详细的解决方案。重点解析了YAML配置文件的结构陷阱、URDF/XACRO中关键标签的正确写法、Launch文件的启动顺序管理,并分享了实用的调试命令与故障排查思路,帮助开发者高效避坑,实现流畅的关节运动控制。

q5r6s7的博客 969

【C++】从libevent到asio:主流C++网络库的演进与实战选型指南

本文深入解析了主流C++网络库的演进与实战选型。通过对比libevent、libev、libuv和asio等核心库的设计哲学(Reactor vs. Proactor)、代码风格及适用场景,为开发者提供了清晰的选型指南。文章强调,选型关键并非绝对性能,而是编程模型、跨平台需求与团队技术栈的匹配度,并特别推荐asio作为拥抱现代C++特性(如协程)的未来之选。

u0v1w2x3的博客 793

实战演练:基于Veristand Custom Device的硬件在环(HIL)数据流控制模块开发

本文详细介绍了基于Veristand Custom Device的硬件在环(HIL)数据流控制模块开发实战。通过LabVIEW环境配置、动态路由逻辑构建、实时处理核心开发及性能优化等关键步骤,帮助工程师快速掌握定制化HIL测试系统的开发技巧,提升测试效率与准确性。

weixin_29206669的博客 475

为什么Node.js的net模块只能跑1.3GB/s?完整解析turbo-net:底层高性能TCP网络库

Node.js 里写 TCP 服务,`net` 模块是首选,但它在高吞吐场景下只能跑到 1.3GB/s。而 [turbo-net](https://link.gitcode.com/i/5235a615b45195b8b47a7b174c26d9a5) 这个**底层高性能 TCP 网络库**,通过直接驱动 libuv、复用缓冲区、支持散列写入,把同样的 Echo 服务吞吐提升到 **3.4GB/s

gitblog_00138的博客 676

Vectorless dynamic动态功耗分析——Voltus

power 计算工具会根据设计信息和用户提供的activity和switching约束来生成虚拟的worst-case的power vector,难点在于哪些instances视为switching,在没有仿真的前提下如何确定开关的时间,使用timing文件(TWF)

qq_44347276的博客 2787

delphi android发送与接收广播

在发送广播时,使用`SendBroadcast`函数,并传入广播的Action。在接收广播时,创建一个继承自`TAndroidBroadcastReceiver`的类,并在`onReceive`方法中处理接收到的广播。然后,使用`RegisterBroadcastReceiver`函数注册广播接收器,并在`UnregisterBroadcastReceiver`函数中取消注册。请注意替换示例代码中的`YOUR_ACTION`为实际的广播Action。// 处理接收到的广播。

GuoGuoABC 1207

【7天精通】比libevent更易用的C/C++网络库libhv从入门到实战

> 官方文档:https://gitcode.com/libhv/libhv/wikis/home

gitblog_01412的博客 1211

GameFramework教程✨六、怎样加载一个3D UI

怎样加载一个3D UI

星河造梦坊 1581

LibProNet单进程处理400万TCP长连接的测试

一、前言 LibProNet是一个开源的C++网络通信引擎,它由一套网络库、一个消息框架和一些有用的网络编程套件构成。与其他著名的网络库诸如libevent/libuv/asio相比,LibProNet更加简洁清晰,容易使用。 LibProNet的工程地址为:https://github.com/libpronet/libpronet 我们今天测试的是LibProNet的网络库模块,目的是为了验证...

dhhome2006的博客 1055

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

国产开源库libhv为何能被awesome-c和awesome-cpp收录

近日,国产开源库libhv为awesome-c、awesome-cpp所收录,让我们看一下这个异军突起的libhv库究竟有何出色之处以及它和libevent、libev、libuv这些老牌网络库有何不同。

HW的博客 8750

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Window下,Cmake编译libhv为Win32

libhv项目:libhv: 🔥 比libevent、libuv更易用的国产网络库,用来开发 TCP/UDP/SSL/HTTP/WebSocket/MQTT 客户端/服务端 (gitee.com) Cmake下载:Download | CMake 步骤: libhv下载后,在 \libhv 下创建文件夹 win32。 打开 Cmake,按如图填写: 之后点击 Configure 然后选择自己的 VS 版本,再第二项选择 Win32: 再点击 Finish,等生成好后点击 Generate

tofu的博客 1814

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

turbo-net完整API参考手册:createServer、connect、read、write、writev详解

turbo-net 是一款面向 Node.js 的底层(Low level)TCP 网络库,提供 createServer、connect、read、write、writev 五大核心 API,帮助开发者写出高性能、低内存占用的 TCP 服务。本手册将带你从零开始,快速掌握它的全部接口与实战技巧。 ## 什么是 turbo-net?适合谁用? turbo-net 用 C 语言(N-API)直接

gitblog_00352的博客 658

开源项目推荐:C/C++网络库(asio/muduo/poco/libevent/libuv/libhv/workflow/acl/HP-Socket/FxSocket/HslCommunica等等)

libcurl是免费的轻量级的客户端网络库,支持DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, Telnet, TFTP. 支持SSL, HTTP POST, HTTP PUT, FTP上传, HTTP form上传,代理,cookies, 用户名与密码认证。2、打开vs工程,把debug模式下,输出的文件名后缀加d。

$firecat利白的代码足迹$ 5890

2025最详libhv入门指南:从0到1构建高性能网络应用

你是否还在为选择复杂的网络库而头疼?面对libevent、libuv的陡峭学习曲线望而却步?本文将带你零基础掌握比libevent更易用、比asio更轻量的高性能网络库——libhv,通过30分钟实战教学,让你从环境搭建到开发TCP/HTTP应用全程无忧。 读完本文你将获得: - 3分钟完成跨平台环境配置的秘诀 - 5行代码实现TCP回声服务器的极简方案 - 10分钟构建RESTful API服...

gitblog_01418的博客 861

libhv教程01--介绍与体验

介绍与体验 名称由来 libhv是一个类似于libevent、libev、libuv的跨平台网络库,提供了带非阻塞IO和定时器的事件循环。 libhv的名称也正是继承此派,寓意高性能的事件循环High-performance event loop library。 libhv能干什么 编写跨平台c/c++程序; 基于TCP/UDP开发自定义协议网络程序; 编写HTTP客户端/服务端程序; 参考学习价值; libhv和libevent、libev、libuv有什么不同 libevent最为古老、有历史包

HW的博客 1万+

高并发rpc的http1.1客户端

在上传信息的应用中,或者RPC应用中,http client很重要,但是curl满足不了需求,所以需要一个更快的客户端,于是有了LibNet

robinfoxnan的专栏 2667
上一篇: TinyXml库的基本操作
下一篇: libuv库TCP echo-server
CodeHeng
博客等级 码龄12年 37粉丝 91原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值