转自:http://blog.csdn.net/wqvbjhc/article/details/25923481

   本人一直在寻找一个跨平台的网络库,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,支持上万链接数的,网上找到的都没合适我的,没办法只能参照各例子自己封装了。

  1 /***************************************
  2 * @file     tcpsocket.h
  3 * @brief    基于libuv封装的tcp服务器与客户端,使用log4z作日志工具
  4 * @details
  5 * @author   phata, 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
  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.csdn.net/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 }

代码已上传到git: https://github.com/wqvbjhc/libuv_tcp

 

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

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