转自: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出错,未找到原因
服务器可以接收几十路连接。万百上千路未测试过,因为没有模拟环境。