node.js的单线程异步模式的在Windows下的IOCP实现
先看看的node.js的比较有趣特征:
(摘自http://baike.baidu.com/view/3974030.htm)
“Node采用了一个称为“事件循环(event loop)”的架构,使得编写可扩展性高的服务器变得既容易又安全。提高服务器性能的技巧有多种多样。Node选择了一种既能提高性能,又能减低开发复杂度的架构。这是一个非常重要的特性。并发编程通常很复杂且布满地雷。Node绕过了这些,但仍提供很好的性能。
Node采用一系列“非阻塞”库来支持事件循环的方式。本质上就是为文件系统、数据库之类的资源提供接口。向文件系统发送一个请求时,无需等待硬盘(寻址并检索文件),硬盘准备好的时候非阻塞接口会通知Node。”
查看Node的代码,可以看到它使用一个单一主线程进行工作(libuv,在Windows下是IOCP,Linux下是epoll等等),将其它费时的操作比如文件IO等通过额外的线程库(libeio/libev)来实现。
以下是纯粹Windows下的服务程序的开发实例,里是一个相对简单的实现。
View Code
1 #include <winsock2.h> 2 #include <windows.h> 3 #include <mswsock.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <malloc.h> 7 #include <time.h> 8 #include <process.h> 9 10 #define TCP_TYPE_LISTEN 1 // 监听 11 #define TCP_TYPE_ACCEPT 2 12 #define TCP_TYPE_IN 3 // 接受的连接 13 #define TCP_TYPE_OUT 4 // 连接到外部服务器 14 15 #define TCP_EV_ACCEPT 1 16 #define TCP_EV_CONNECT 2 17 #define TCP_EV_CLOSE 3 18 #define TCP_EV_SEND 4 // data sent 19 #define TCP_EV_RECEIVE 5 // if returns -1, the sock will be CLOSED 20 #define TCP_EV_CUSTOM 6 // custom event 21 #define TCP_EV_TIMER 7 // abount 100ms 22 23 // 事件回调函数 24 // TCP_EV_RECEIVE:,msgData和msgLen为收到的数据和数据大小 25 // TCP_EV_CUSTOM: msgData为传入的key 26 typedef int (CALLBACK TCPSOCKETEVENTPROC)(int sockIdx, int msgCode, UCHAR *msgData, int msgLen); 27 28 BOOL tcp_startup(int maxSockets, TCPSOCKETEVENTPROC *lpfnEventProc); 29 void tcp_cleanup(); 30 31 int tcp_listen(const char *ip, u_short port, TCPSOCKETEVENTPROC *lpfnEventProc); 32 int tcp_connect(const char *ip, u_short port, TCPSOCKETEVENTPROC *lpfnEventProc); 33 BOOL tcp_send(int sockIdx, const void *data1, int dataLen1, const void *data2, int dataLen2); 34 35 void tcp_close(int sockIdx); 36 37 void tcp_pause(int sockIdx); 38 void tcp_resume(int sockIdx); 39 40 void tcp_setUserData(int sockIdx, void *lpUserData); 41 void *tcp_getUserData(int sockIdx); 42 43 BOOL tcp_getSendStat(int sockIdx, int *sendingSize, int *bufferedSize); 44 void tcp_setExpectPackLen(int sockIdx, int packLen); 45 46 void tcp_postEvent(void *key); 47 48 BOOL tcp_getInfo(int sockIdx, struct tcp_info *tsi); 49 50 struct tcp_info 51 { 52 SOCKET sock; 53 LONG type; 54 LONG connecting; 55 LONG sending; 56 LONG paused; 57 LONG closing; 58 struct 59 { 60 char ip[20]; 61 u_short port; 62 } peerAddr, hostAddr; 63 TCPSOCKETEVENTPROC *lpfnEventProc; 64 LPVOID lpUserData; 65 66 int sockIdxListen; 67 time_t lastReceiveTime; 68 time_t lastSendTime; 69 time_t acceptTime; 70 time_t connectTime; 71 }; 72 73 74 struct tcp_buf 75 { 76 int dlen; 77 int alen; 78 UCHAR *data; 79 }; 80 81 static __inline void buf_free(struct tcp_buf *bf) 82 { 83 if (bf->data != NULL) 84 free(bf->data); 85 bf->dlen = 0; 86 bf->alen = 0; 87 bf->data = NULL; 88 } 89 90 static __inline void buf_swap(struct tcp_buf *bf1, struct tcp_buf *bf2) 91 { 92 struct tcp_buf bf; 93 94 bf = *bf1; 95 *bf1 = *bf2; 96 *bf2 = bf; 97 } 98 99 static BOOL buf_alloc(struct tcp_buf *bf, int alloc) 100 { 101 if (bf->alen < alloc + 1) 102 { 103 const int BLOCK_SIZE = 1024; 104 int newAlloc; 105 UCHAR *newBuff; 106 107 if (alloc < BLOCK_SIZE) 108 newAlloc = BLOCK_SIZE; 109 else 110 newAlloc = (alloc / BLOCK_SIZE + 1) * BLOCK_SIZE; 111 112 newBuff = (UCHAR *)malloc(newAlloc); 113 if (newBuff == NULL) return FALSE; 114 if (bf->data) 115 { 116 if (bf->dlen) 117 memcpy(newBuff, bf->data, bf->dlen); 118 free(bf->data); 119 } 120 bf->data = newBuff; 121 bf->alen = newAlloc; 122 } 123 return TRUE; 124 } 125 126 static BOOL buf_append(struct tcp_buf *bf, const void *data, int dlen) 127 { 128 if (!buf_alloc(bf, bf->dlen + dlen + 1)) 129 return FALSE; 130 131 memcpy(bf->data + bf->dlen, data, dlen); 132 bf->dlen += dlen; 133 return TRUE; 134 } 135 136 static void buf_erase(struct tcp_buf *bf, int erase_pos, int erase_len) 137 { 138 if (erase_pos >= 0 && 139 erase_pos < bf->dlen && 140 (erase_pos + erase_len) <= bf->dlen) 141 { 142 if ((erase_pos + erase_len) < bf->dlen) 143 memmove(bf->data + erase_pos, 144 bf->data + erase_pos + erase_len, 145 bf->dlen - erase_pos - erase_len); 146 bf->dlen -= erase_len; 147 } 148 } 149 150 // ----------------------------------------------------------------------- 151 // socket status 152 #define STAT_CONNECTING 0x01 153 #define STAT_PAUSED 0x02 154 #define STAT_CLOSING 0x04 155 #define STAT_RECEIVING 0x10 156 #define STAT_SENDING 0x20 157 158 struct tcp_socket 159 { 160 UINT64 id; // opt future 161 SOCKET sock; 162 LONG type; 163 LONG stat; 164 struct sockaddr_in addr; 165 TCPSOCKETEVENTPROC *lpfnEventProc; 166 PVOID lpUserData; 167 LONG expectPackLen; 168 169 OVERLAPPED ovlpSend; 170 OVERLAPPED ovlpReceive; 171 OVERLAPPED ovlpConnect; 172 OVERLAPPED ovlpClose; 173 174 struct tcp_buf bufSending; 175 struct tcp_buf bufToSend; 176 struct tcp_buf bufRecv; 177 int sockIdxListen; 178 int sockIdxAccept; 179 time_t lastReceiveTime; 180 time_t lastSendTime; 181 time_t acceptTime; 182 time_t connectTime; 183 }; 184 185 static HANDLE g_completionPort = NULL; 186 static OVERLAPPED g_ovlpExit = { 0 }; 187 188 static struct tcp_socket **g_sockets = NULL; 189 static int g_maxSockets = 0; 190 static TCPSOCKETEVENTPROC *g_lpfnEventProc = NULL; 191 static HANDLE g_thread = NULL; 192 193 static LPFN_CONNECTEX g_lpfnConnectEx = NULL; 194 static LPFN_ACCEPTEX g_lpfnAcceptEx = NULL; 195 static LPFN_DISCONNECTEX g_lpfnDisconnectEx = NULL; 196 197 198 void tcp_setUserData(int sockIdx, void *lpUserData) 199 { 200 if (sockIdx >= 0 && sockIdx < g_maxSockets && g_sockets[sockIdx]) 201 g_sockets[sockIdx]->lpUserData = lpUserData; 202 } 203 204 void *tcp_getUserData(int sockIdx) 205 { 206 return ((sockIdx >= 0 && sockIdx < g_maxSockets && g_sockets[sockIdx]) 207 ? g_sockets[sockIdx]->lpUserData : NULL); 208 } 209 210 void tcp_setExpectPackLen(int sockIdx, int packLen) 211 { 212 if (sockIdx >= 0 && sockIdx < g_maxSockets && g_sockets[sockIdx]) 213 g_sockets[sockIdx]->expectPackLen = packLen; 214 } 215 216 BOOL tcp_getSendStat(int sockIdx, int *sendingSize, int *bufferedSize) 217 { 218 *sendingSize = 0; 219 *bufferedSize = 0; 220 221 if (sockIdx >= 0 && sockIdx < g_maxSockets && g_sockets[sockIdx]) 222 { 223 if (g_sockets[sockIdx]->stat & STAT_SENDING) 224 *sendingSize = g_sockets[sockIdx]->bufSending.dlen; 225 *bufferedSize = g_sockets[sockIdx]->bufToSend.dlen; 226 return TRUE; 227 } 228 229 return FALSE; 230 } 231 232 // called from outside threads 233 void tcp_postEvent(void *key) 234 { 235 PostQueuedCompletionStatus(g_completionPort, 0, (ULONG_PTR)(-11), (LPOVERLAPPED)key); 236 } 237 238 BOOL tcp_getInfo(int sockIdx, struct tcp_info *tsi) 239 { 240 struct sockaddr_in addr; 241 int addrLen = sizeof(tsi->hostAddr); 242 243 memset(tsi, 0, sizeof(*tsi)); 244 tsi->sock = INVALID_SOCKET; 245 tsi->sockIdxListen = -1; 246 247 if (sockIdx < 0 || sockIdx >= g_maxSockets || !g_sockets[sockIdx]) 248 return FALSE; 249 250 tsi->sock = g_sockets[sockIdx]->sock; 251 tsi->type = g_sockets[sockIdx]->type; 252 tsi->connecting = g_sockets[sockIdx]->stat & STAT_CONNECTING; 253 tsi->sending = g_sockets[sockIdx]->stat & STAT_SENDING; 254 tsi->paused = g_sockets[sockIdx]->stat & STAT_PAUSED; 255 tsi->closing = g_sockets[sockIdx]->stat & STAT_CLOSING; 256 getpeername(g_sockets[sockIdx]->sock, (struct sockaddr *)&addr, &addrLen); 257 strcpy_s(tsi->peerAddr.ip, 20, inet_ntoa(addr.sin_addr)); 258 tsi->peerAddr.port = ntohs(addr.sin_port); 259 getsockname(g_sockets[sockIdx]->sock, (struct sockaddr *)&addr, &addrLen); 260 strcpy_s(tsi->hostAddr.ip, 20, inet_ntoa(addr.sin_addr)); 261 tsi->hostAddr.port = ntohs(addr.sin_port); 262 tsi->lpfnEventProc = g_sockets[sockIdx]->lpfnEventProc; 263 tsi->lpUserData = g_sockets[sockIdx]->lpUserData; 264 tsi->sockIdxListen = g_sockets[sockIdx]->sockIdxListen; 265 tsi->lastReceiveTime = g_sockets[sockIdx]->lastReceiveTime; 266 tsi->lastSendTime = g_sockets[sockIdx]->lastSendTime; 267 tsi->acceptTime = g_sockets[sockIdx]->acceptTime; 268 tsi->connectTime = g_sockets[sockIdx]->connectTime; 269 270 return TRUE; 271 } 272 273 static void tcp_clean(int sockIdx) 274 { 275 g_sockets[sockIdx]->type = 0; 276 g_sockets[sockIdx]->stat = 0; 277 memset(&g_sockets[sockIdx]->addr, 0, sizeof(g_sockets[sockIdx]->addr)); 278 g_sockets[sockIdx]->lpUserData = NULL; 279 280 memset(&g_sockets[sockIdx]->ovlpSend, 0, sizeof(OVERLAPPED)); 281 memset(&g_sockets[sockIdx]->ovlpReceive, 0, sizeof(OVERLAPPED)); 282 memset(&g_sockets[sockIdx]->ovlpConnect, 0, sizeof(OVERLAPPED)); 283 memset(&g_sockets[sockIdx]->ovlpClose, 0, sizeof(OVERLAPPED)); 284 g_sockets[sockIdx]->bufSending.dlen = 0; 285 g_sockets[sockIdx]->bufToSend.dlen = 0; 286 g_sockets[sockIdx]->bufRecv.dlen = 0; 287 g_sockets[sockIdx]->sockIdxListen = -1; 288 g_sockets[sockIdx]->sockIdxAccept = -1; 289 g_sockets[sockIdx]->lastReceiveTime = 0; 290 g_sockets[sockIdx]->lastSendTime = 0; 291 g_sockets[sockIdx]->acceptTime = 0; 292 g_sockets[sockIdx]->connectTime = 0; 293 } 294 295 static int tcp_new(int type) 296 { 297 int i, sockIdx; 298 299 for (i=0, sockIdx=-1; i<g_maxSockets; i++) 300 { 301 if (!g_sockets[i] || !g_sockets[i]->type) 302 { 303 sockIdx = i; 304 break; 305 } 306 } 307 308 if (sockIdx < 0) return -1; 309 310 if (!g_sockets[sockIdx]) 311 { 312 g_sockets[sockIdx] = (struct tcp_socket *)malloc(sizeof(struct tcp_socket)); 313 if (!g_sockets[sockIdx]) return -1; 314 memset(g_sockets[sockIdx], 0, sizeof(struct tcp_socket)); 315 g_sockets[sockIdx]->sock = INVALID_SOCKET; 316 } 317 318 tcp_clean(sockIdx); 319 320 g_sockets[sockIdx]->type = type; 321 g_sockets[sockIdx]->lpUserData = NULL; 322 323 return sockIdx; 324 } 325 326 static void tcp_release(int sockIdx, BOOL notify) 327 { 328 if (sockIdx < 0 || sockIdx >= g_maxSockets || 329 !g_sockets[sockIdx] || !g_sockets[sockIdx]->type) 330 return; 331 332 if (g_sockets[sockIdx]->sock != INVALID_SOCKET) 333 { 334 CancelIo((HANDLE)g_sockets[sockIdx]->sock); 335 closesocket(g_sockets[sockIdx]->sock); 336 g_sockets[sockIdx]->sock = INVALID_SOCKET; 337 } 338 339 if (notify && g_sockets[sockIdx]->type && 340 g_sockets[sockIdx]->type != TCP_TYPE_ACCEPT && 341 g_sockets[sockIdx]->lpfnEventProc) 342 g_sockets[sockIdx]->lpfnEventProc(sockIdx, TCP_EV_CLOSE, NULL, 0); 343 344 tcp_clean(sockIdx); 345 } 346 347 void tcp_close(int sockIdx) 348 { 349 if (sockIdx < 0 || sockIdx >= g_maxSockets || 350 !g_sockets[sockIdx] || !g_sockets[sockIdx]->type) 351 return; 352 353 g_sockets[sockIdx]->stat |= STAT_CLOSING; 354 355 PostQueuedCompletionStatus(g_completionPort, 0, sockIdx, (LPOVERLAPPED)&g_sockets[sockIdx]->ovlpClose); 356 } 357 358 BOOL tcp_send(int sockIdx, 359 const void *data1, int dataLen1, 360 const void *data2, int dataLen2) 361 { 362 if (sockIdx < 0 || sockIdx >= g_maxSockets || 363 !g_sockets[sockIdx] || 364 (g_sockets[sockIdx]->type != TCP_TYPE_IN && 365 g_sockets[sockIdx]->type != TCP_TYPE_OUT) || 366 g_sockets[sockIdx]->sock == INVALID_SOCKET || 367 g_sockets[sockIdx]->stat & 0x0F) 368 return FALSE; 369 370 if (g_sockets[sockIdx]->stat & STAT_SENDING) 371 { 372 if (g_sockets[sockIdx]->bufToSend.dlen > 10*1024*1024) return FALSE; 373 374 if (data1 && dataLen1) 375 buf_append(&g_sockets[sockIdx]->bufToSend, data1, dataLen1); 376 if (data2 && dataLen2) 377 buf_append(&g_sockets[sockIdx]->bufToSend, data2, dataLen2); 378 379 return TRUE; 380 } 381 382 if (data1 && dataLen1) 383 buf_append(&g_sockets[sockIdx]->bufSending, data1, dataLen1); 384 if (data2 && dataLen2) 385 buf_append(&g_sockets[sockIdx]->bufSending, data2, dataLen2); 386 387 if (!g_sockets[sockIdx]->bufSending.dlen) return TRUE; 388 389 g_sockets[sockIdx]->stat |= STAT_SENDING; 390 391 if (!WriteFile( 392 (HANDLE)g_sockets[sockIdx]->sock, 393 g_sockets[sockIdx]->bufSending.data, 394 g_sockets[sockIdx]->bufSending.dlen, 395 NULL, 396 (LPOVERLAPPED)&g_sockets[sockIdx]->ovlpSend)) 397 { 398 DWORD lastErr = GetLastError(); 399 if (lastErr != ERROR_IO_PENDING) 400 { 401 PostQueuedCompletionStatus(g_completionPort, 0, sockIdx, 402 (LPOVERLAPPED)&g_sockets[sockIdx]->ovlpClose); 403 return FALSE; 404 } 405 } 406 407 return TRUE; 408 } 409 410 static void tcp_doReceive(int sockIdx) 411 { 412 int bytesToRead; 413 414 if (g_sockets[sockIdx]->expectPackLen > 0) 415 { 416 bytesToRead = max(128, g_sockets[sockIdx]->expectPackLen - g_sockets[sockIdx]->bufRecv.dlen); 417 buf_alloc(&g_sockets[sockIdx]->bufRecv, g_sockets[sockIdx]->bufRecv.dlen + bytesToRead + 128); 418 g_sockets[sockIdx]->expectPackLen = 0; 419 } 420 else 421 { 422 bytesToRead = 1600; 423 buf_alloc(&g_sockets[sockIdx]->bufRecv, g_sockets[sockIdx]->bufRecv.dlen + bytesToRead); 424 } 425 426 g_sockets[sockIdx]->stat |= STAT_RECEIVING; 427 428 if (!ReadFile((HANDLE)g_sockets[sockIdx]->sock, 429 g_sockets[sockIdx]->bufRecv.data + g_sockets[sockIdx]->bufRecv.dlen, 430 bytesToRead, NULL, (LPOVERLAPPED)&g_sockets[sockIdx]->ovlpReceive)) 431 { 432 DWORD lastErr = GetLastError(); 433 if (lastErr != ERROR_IO_PENDING) 434 { 435 PostQueuedCompletionStatus(g_completionPort, 0, sockIdx, 436 (LPOVERLAPPED)&g_sockets[sockIdx]->ovlpClose); 437 } 438 } 439 } 440 441 void tcp_pause(int sockIdx) 442 { 443 if (sockIdx < 0 || sockIdx >= g_maxSockets || !g_sockets[sockIdx]) 444 return; 445 446 g_sockets[sockIdx]->stat |= STAT_PAUSED; 447 } 448 449 void tcp_resume(int sockIdx) 450 { 451 if (sockIdx < 0 || sockIdx >= g_maxSockets || !g_sockets[sockIdx]) 452 return; 453 454 g_sockets[sockIdx]->stat &= ~STAT_PAUSED; 455 456 if (!(g_sockets[sockIdx]->stat & STAT_RECEIVING)) 457 tcp_doReceive(sockIdx); 458 } 459 460 static int tcp_accept(int sockIdxListen) 461 { 462 SOCKET newSocket; 463 int sockIdx; 464 465 newSocket = socket(AF_INET, SOCK_STREAM, 0); 466 if (newSocket == INVALID_SOCKET) return -1; 467 468 sockIdx = tcp_new(TCP_TYPE_ACCEPT); 469 if (sockIdx < 0) 470 { 471 closesocket(newSocket); 472 return -1; 473 } 474 475 g_sockets[sockIdx]->sock = newSocket; 476 g_sockets[sockIdx]->sockIdxListen = sockIdxListen; 477 g_sockets[sockIdx]->lpfnEventProc = g_sockets[sockIdxListen]->lpfnEventProc; 478 479 g_sockets[sockIdxListen]->sockIdxAccept = sockIdx; 480 buf_alloc(&g_sockets[sockIdxListen]->bufRecv, 512); 481 if (!g_lpfnAcceptEx( 482 g_sockets[sockIdxListen]->sock, g_sockets[sockIdx]->sock, 483 g_sockets[sockIdxListen]->bufRecv.data, 0, 484 sizeof(struct sockaddr_in) + 16, sizeof(struct sockaddr_in) + 16, 485 NULL, (LPOVERLAPPED)&g_sockets[sockIdxListen]->ovlpReceive)) 486 { 487 DWORD lastErr = WSAGetLastError(); 488 if (lastErr != ERROR_IO_PENDING) 489 { 490 PostQueuedCompletionStatus(g_completionPort, 0, sockIdx, 491 (LPOVERLAPPED)&g_sockets[sockIdx]->ovlpClose); 492 g_sockets[sockIdxListen]->stat |= STAT_CLOSING; // no notify 493 PostQueuedCompletionStatus(g_completionPort, 0, sockIdxListen, 494 (LPOVERLAPPED)&g_sockets[sockIdxListen]->ovlpClose); 495 return -1; 496 } 497 } 498 499 return sockIdx; 500 } 501 502 int tcp_listen(const char *ip, u_short port, TCPSOCKETEVENTPROC *lpfnEventProc) 503 { 504 SOCKET listenSocket; 505 struct sockaddr_in addr; 506 int sockIdx; 507 508 if (!g_maxSockets || !g_sockets) return -1; 509 510 if (port < 80 || port >= 65535) return -1; 511 512 listenSocket = socket(AF_INET, SOCK_STREAM, 0); 513 if (listenSocket == INVALID_SOCKET) return -1; 514 515 memset(&addr, 0, sizeof(addr)); 516 addr.sin_family = AF_INET; 517 addr.sin_addr.s_addr = inet_addr(ip); 518 if (addr.sin_addr.s_addr == INADDR_NONE) 519 addr.sin_addr.s_addr = INADDR_ANY; 520 addr.sin_port = htons(port); 521 if (bind(listenSocket, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) 522 { 523 closesocket(listenSocket); 524 return -1; 525 } 526 if (listen(listenSocket, SOMAXCONN) == SOCKET_ERROR) 527 { 528 closesocket(listenSocket); 529 return -1; 530 } 531 532 sockIdx = tcp_new(TCP_TYPE_LISTEN); 533 if (sockIdx < 0) 534 { 535 closesocket(listenSocket); 536 return -1; 537 } 538 539 g_sockets[sockIdx]->sock = listenSocket; 540 g_sockets[sockIdx]->lpfnEventProc = (lpfnEventProc ? lpfnEventProc : g_lpfnEventProc); 541 542 CreateIoCompletionPort((HANDLE)g_sockets[sockIdx]->sock, g_completionPort, (ULONG_PTR)sockIdx, 0); 543 tcp_accept(sockIdx); 544 545 return sockIdx; 546 } 547 548 int tcp_connect(const char *ip, u_short port, TCPSOCKETEVENTPROC *lpfnEventProc) 549 { 550 SOCKET connectSocket; 551 struct sockaddr_in addr; 552 int sockIdx; 553 554 if (!g_maxSockets || !g_sockets) return -1; 555 556 connectSocket = socket(AF_INET, SOCK_STREAM, 0); 557 if (connectSocket == INVALID_SOCKET) return -1; 558 559 memset(&addr, 0, sizeof(addr)); 560 addr.sin_family = AF_INET; 561 addr.sin_addr.s_addr = ADDR_ANY; 562 addr.sin_port = htons(0); 563 if (bind(connectSocket, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) 564 { 565 closesocket(connectSocket); 566 return -1; 567 } 568 569 sockIdx = tcp_new(TCP_TYPE_OUT); 570 if (sockIdx < 0) 571 { 572 closesocket(connectSocket); 573 return -1; 574 } 575 576 g_sockets[sockIdx]->sock = connectSocket; 577 g_sockets[sockIdx]->lpfnEventProc = (lpfnEventProc ? lpfnEventProc : g_lpfnEventProc); 578 CreateIoCompletionPort((HANDLE)g_sockets[sockIdx]->sock, g_completionPort, (ULONG_PTR)sockIdx, 0); 579 580 memset(&g_sockets[sockIdx]->addr, 0, sizeof(addr)); 581 g_sockets[sockIdx]->addr.sin_family = AF_INET; 582 g_sockets[sockIdx]->addr.sin_addr.s_addr = inet_addr(ip); 583 g_sockets[sockIdx]->addr.sin_port = htons(port); 584 585 g_sockets[sockIdx]->stat |= STAT_CONNECTING; 586 587 if (!g_lpfnConnectEx(g_sockets[sockIdx]->sock, 588 (struct sockaddr *)&g_sockets[sockIdx]->addr, sizeof(g_sockets[sockIdx]->addr), 589 NULL, 0, NULL, (LPOVERLAPPED)&g_sockets[sockIdx]->ovlpConnect) 590 && WSAGetLastError() != ERROR_IO_PENDING) 591 { 592 g_sockets[sockIdx]->stat |= STAT_CLOSING; // no notify 593 PostQueuedCompletionStatus(g_completionPort, 0, sockIdx, 594 (LPOVERLAPPED)&g_sockets[sockIdx]->ovlpClose); 595 return -1; 596 } 597 598 return sockIdx; 599 } 600 601 static BOOL tcp_processReceivedData(int sockIdx) 602 { 603 INT continueProcess, processed; 604 605 continueProcess = 1; 606 do 607 { 608 processed = g_sockets[sockIdx]->lpfnEventProc(sockIdx, TCP_EV_RECEIVE, 609 g_sockets[sockIdx]->bufRecv.data, g_sockets[sockIdx]->bufRecv.dlen); 610 if (processed < 0) 611 { 612 g_sockets[sockIdx]->stat |= STAT_CLOSING; 613 PostQueuedCompletionStatus(g_completionPort, 0, sockIdx, 614 (LPOVERLAPPED)&g_sockets[sockIdx]->ovlpClose); 615 continueProcess = -1; 616 } 617 else if (processed > 0) 618 { 619 buf_erase(&g_sockets[sockIdx]->bufRecv, 0, processed); 620 continueProcess = (g_sockets[sockIdx]->bufRecv.dlen > 0 ? 1 : 0); 621 } 622 else 623 continueProcess = 0; 624 } 625 while (continueProcess == 1); 626 627 return continueProcess != -1; 628 } 629 630 static void tcp_checkIdleClients() 631 { 632 static time_t _lastCheckTime = 0; 633 time_t currTime; 634 635 time(&currTime); 636 if (currTime - _lastCheckTime < 2) return; 637 _lastCheckTime = currTime; 638 639 if (g_sockets) 640 { 641 int i; 642 643 for (i=0; i<g_maxSockets; i++) 644 { 645 if (!g_sockets[i]) break; 646 if (g_sockets[i]->type != TCP_TYPE_IN) continue; 647 648 if (!g_sockets[i]->lastReceiveTime && 649 currTime - g_sockets[i]->acceptTime >= 20) 650 tcp_release(i, FALSE); 651 } 652 } 653 } 654 655 #define IsValidSockIdx(sockIdx) (sockIdx >= 0 && sockIdx < g_maxSockets && g_sockets[sockIdx]) 656 657 static unsigned __stdcall tcp_workerThread(void* pArguments) 658 { 659 BOOL hasEntry; 660 OVERLAPPED *lpo; 661 DWORD dwBytes; 662 ULONG_PTR key; 663 int sockIdx, sockIdxAccepted, lastErr; 664 DWORD currTickCount, nextTimerTickCount; 665 666 nextTimerTickCount = GetTickCount() + 200; 667 668 while (1) 669 { 670 hasEntry = GetQueuedCompletionStatus(g_completionPort, &dwBytes, &key, &lpo, 100); 671 672 currTickCount = GetTickCount(); 673 if (currTickCount > nextTimerTickCount) 674 { 675 nextTimerTickCount = currTickCount + 100; 676 if (g_lpfnEventProc) 677 g_lpfnEventProc(-1, TCP_EV_TIMER, NULL, 0); 678 } 679 680 if (!lpo && !hasEntry) 681 { 682 lastErr = GetLastError(); 683 //if (lastErr && lastErr != WAIT_TIMEOUT && lastErr != ERROR_IO_PENDING) ; 684 685 tcp_checkIdleClients(); 686 continue; 687 } 688 689 sockIdx = (int)key; 690 691 if (lpo == &g_ovlpExit) break; 692 693 if (sockIdx == -11) // custom event 694 { 695 if (g_lpfnEventProc) 696 g_lpfnEventProc(0, TCP_EV_CUSTOM, (UCHAR *)lpo, 0); 697 continue; 698 } 699 700 if (sockIdx == -111) // timer event 701 { 702 currTickCount = GetTickCount(); 703 if (currTickCount > nextTimerTickCount) 704 { 705 nextTimerTickCount = currTickCount + 100; 706 if (g_lpfnEventProc) 707 g_lpfnEventProc(-1, TCP_EV_TIMER, NULL, 0); 708 } 709 continue; 710 } 711 712 if (!hasEntry) // IO operation failed, ie: socket closed 713 { 714 if (IsValidSockIdx(sockIdx)) 715 { 716 if (g_sockets[sockIdx]->type == TCP_TYPE_LISTEN) 717 tcp_accept(sockIdx); 718 else 719 tcp_release(sockIdx, TRUE); 720 } 721 continue; 722 } 723 724 if (!IsValidSockIdx(sockIdx)) continue; 725 726 if (lpo == &g_sockets[sockIdx]->ovlpConnect) 727 { 728 if (g_sockets[sockIdx]->stat & STAT_CONNECTING && 729 g_sockets[sockIdx]->type == TCP_TYPE_OUT) 730 { 731 g_sockets[sockIdx]->stat &= ~STAT_CONNECTING; 732 time(&g_sockets[sockIdx]->connectTime); 733 734 if (g_sockets[sockIdx]->lpfnEventProc(sockIdx, TCP_EV_CONNECT, NULL, 0) < 0) 735 tcp_release(sockIdx, FALSE); 736 else 737 tcp_doReceive(sockIdx); 738 } 739 } 740 else if (lpo == &g_sockets[sockIdx]->ovlpClose) 741 { 742 tcp_release(sockIdx, g_sockets[sockIdx]->stat & STAT_CLOSING); 743 } 744 else if (lpo == &g_sockets[sockIdx]->ovlpSend) 745 { 746 g_sockets[sockIdx]->stat &= ~STAT_SENDING; 747 748 time(&g_sockets[sockIdx]->lastSendTime); 749 750 // socket关闭以后仍然可能收到此消息 751 //if (dwBytes != g_sockets[sockIdx]->bufSending.dlen); 752 753 g_sockets[sockIdx]->bufSending.dlen = 0; 754 755 if (!(g_sockets[sockIdx]->stat & STAT_CLOSING)) 756 { 757 if (!g_sockets[sockIdx]->bufToSend.dlen) 758 g_sockets[sockIdx]->lpfnEventProc(sockIdx, TCP_EV_SEND, NULL, 0); 759 else 760 { 761 buf_swap(&g_sockets[sockIdx]->bufToSend, &g_sockets[sockIdx]->bufSending); 762 tcp_send(sockIdx, NULL, 0, NULL, 0); 763 } 764 } 765 } 766 else if (lpo == &g_sockets[sockIdx]->ovlpReceive) 767 { 768 switch (g_sockets[sockIdx]->type) 769 { 770 case TCP_TYPE_LISTEN: 771 sockIdxAccepted = g_sockets[sockIdx]->sockIdxAccept; 772 g_sockets[sockIdxAccepted]->type = TCP_TYPE_IN; 773 setsockopt(g_sockets[sockIdxAccepted]->sock, 774 SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, 775 (char *)&g_sockets[sockIdx]->sock, sizeof(SOCKET)); 776 CreateIoCompletionPort((HANDLE)g_sockets[sockIdxAccepted]->sock, 777 g_completionPort, (ULONG_PTR)sockIdxAccepted, 0); 778 time(&g_sockets[sockIdxAccepted]->acceptTime); 779 g_sockets[sockIdx]->lpfnEventProc(sockIdxAccepted, TCP_EV_ACCEPT, NULL, 0); 780 tcp_doReceive(sockIdxAccepted); 781 tcp_accept(sockIdx); 782 break; 783 784 case TCP_TYPE_IN: 785 case TCP_TYPE_OUT: 786 if (dwBytes == 0) // peer closed 787 tcp_release(sockIdx, TRUE); 788 else 789 { 790 g_sockets[sockIdx]->stat &= ~STAT_RECEIVING; 791 time(&g_sockets[sockIdx]->lastReceiveTime); 792 g_sockets[sockIdx]->bufRecv.dlen += dwBytes; 793 794 if (g_sockets[sockIdx]->sock == INVALID_SOCKET || 795 g_sockets[sockIdx]->stat & 0x0F) 796 tcp_release(sockIdx, FALSE); 797 else if (tcp_processReceivedData(sockIdx) && 798 !(g_sockets[sockIdx]->stat & STAT_PAUSED)) 799 tcp_doReceive(sockIdx); 800 } 801 break; 802 } 803 } 804 } 805 806 return 0; 807 } 808 809 static BOOL tcp_prepare() 810 { 811 GUID guidConnectEx = WSAID_CONNECTEX; 812 GUID guidAcceptEx = WSAID_ACCEPTEX; 813 GUID guidDisconnectEx = WSAID_DISCONNECTEX; 814 SOCKET tmpSocket; 815 DWORD dwBytes; 816 817 tmpSocket = socket(AF_INET, SOCK_STREAM, 0); 818 if (tmpSocket == INVALID_SOCKET) return FALSE; 819 WSAIoctl(tmpSocket, 820 SIO_GET_EXTENSION_FUNCTION_POINTER, 821 &guidConnectEx, 822 sizeof(guidConnectEx), 823 &g_lpfnConnectEx, 824 sizeof(g_lpfnConnectEx), 825 &dwBytes, 826 NULL, 827 NULL); 828 WSAIoctl(tmpSocket, 829 SIO_GET_EXTENSION_FUNCTION_POINTER, 830 &guidAcceptEx, 831 sizeof(guidAcceptEx), 832 &g_lpfnAcceptEx, 833 sizeof(g_lpfnAcceptEx), 834 &dwBytes, 835 NULL, 836 NULL); 837 WSAIoctl(tmpSocket, 838 SIO_GET_EXTENSION_FUNCTION_POINTER, 839 &guidDisconnectEx, 840 sizeof(guidDisconnectEx), 841 &g_lpfnDisconnectEx, 842 sizeof(g_lpfnDisconnectEx), 843 &dwBytes, 844 NULL, 845 NULL); 846 closesocket(tmpSocket); 847 848 return (g_lpfnConnectEx && g_lpfnAcceptEx && g_lpfnDisconnectEx); 849 } 850 851 BOOL tcp_startup(int maxSockets, TCPSOCKETEVENTPROC *lpfnEventProc) 852 { 853 if (g_maxSockets) return TRUE; 854 855 if (!tcp_prepare()) return FALSE; 856 857 if (maxSockets < 512) maxSockets = 512; 858 if (maxSockets > 50*1024) maxSockets = 50*1024; 859 860 if (!lpfnEventProc) return FALSE; 861 862 g_maxSockets = maxSockets; 863 g_lpfnEventProc = lpfnEventProc; 864 865 g_completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)NULL, 0); 866 if (g_completionPort == NULL) return FALSE; 867 868 g_sockets = (struct tcp_socket **)calloc(g_maxSockets, sizeof(struct tcp_socket *)); 869 if (!g_sockets) return FALSE; 870 871 g_thread = (HANDLE)_beginthreadex(NULL, 0, tcp_workerThread, NULL, 0, NULL); 872 if (!g_thread) return FALSE; 873 874 return TRUE; 875 } 876 877 void tcp_cleanup() 878 { 879 int i; 880 881 if (!g_maxSockets || !g_sockets) return; 882 883 for (i=0; i<g_maxSockets; i++) 884 { 885 if (!g_sockets[i]) break; 886 g_sockets[i]->stat |= STAT_CLOSING; 887 } 888 for (i=0; i<g_maxSockets; i++) 889 { 890 if (!g_sockets[i]) break; 891 PostQueuedCompletionStatus(g_completionPort, 0, i, &g_sockets[i]->ovlpClose); 892 } 893 894 PostQueuedCompletionStatus(g_completionPort, 0, 0, &g_ovlpExit); 895 WaitForSingleObject(g_thread, INFINITE); 896 CloseHandle(g_thread); 897 g_thread = NULL; 898 899 CloseHandle(g_completionPort); 900 g_completionPort = NULL; 901 902 for (i=0; i<g_maxSockets; i++) 903 { 904 if (!g_sockets[i]) break; 905 906 buf_free(&g_sockets[i]->bufSending); 907 buf_free(&g_sockets[i]->bufToSend); 908 buf_free(&g_sockets[i]->bufRecv); 909 free(g_sockets[i]); 910 } 911 free(g_sockets); 912 g_sockets = NULL; 913 g_maxSockets = 0; 914 }
以上代码是从“网游更新平台”中摘出,运行状况不错。
"网游更新平台"现已开源:https://github.com/zhaozongzhe/gmDev
posted on 2012-12-02 16:09 zhaozongzhe 阅读(1383) 评论(0) 编辑 收藏 举报
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步