void NetAcceptor::Accepts() { _pendingAccepts.resize(NETWORK_DEFAULT_OVERLAPPED_COUNT, nullptr); for (int i = 0; i < NETWORK_DEFAULT_OVERLAPPED_COUNT; ++i) { _pendingAccepts[i] = new AcceptBuffer; PostAccept(_pendingAccepts[i]); } }
///函数:绑定套接字,并投递 accept 请求。 void EasyIocp::InitListenSocket() { //创建listen socket 并bind和listen,然后投递accept请求 SOCKET listenSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); if(listenSock == INVALID_SOCKET) { ErrorSockMessage("EasyIocp::InitListenSocket: create listen socket failed."); assert(FALSE); } //将listen socket绑定到completion port compListen_.SetSocket(listenSock); if( !CreateIoCompletionPort((HANDLE)(listenSock), hCompPort_, (ULONG_PTR)&compListen_, 0) ) { ErrorSysMessage("EasyIocp::InitListenSocket: associate listen socket failed."); assert(FALSE); } if( bind(listenSock, (sockaddr*)&bindAddr_, sizeof(bindAddr_)) != 0 ) { ErrorSockMessage("EasyIocp::InitListenSocket: bind failed."); assert(FALSE); } print("EasyIocp::InitListenSocket: bind to %s:%d.", inet_ntoa(bindAddr_.sin_addr), ntohs(bindAddr_.sin_port)); if( listen(listenSock, EASYIOCP_LISTEN_NUM) != 0 ) { ErrorSockMessage("EasyIocp::InitListenSocket: listen failed."); assert(FALSE); } print("EasyIocp::InitListenSocket: listening."); //开始投递accept请求 GUID guidAcceptEx = WSAID_ACCEPTEX; GUID guidGetAcceptExSockAddrs = WSAID_GETACCEPTEXSOCKADDRS; if( !GetExtendSockFunc(listenSock, &guidAcceptEx, sizeof(guidAcceptEx), &funcAcceptEx_, sizeof(funcAcceptEx_)) ) { ErrorSockMessage("EasyIocp::InitListenSocket: get AcceptEx failed."); assert(FALSE); } if( !GetExtendSockFunc(listenSock, &guidGetAcceptExSockAddrs, sizeof(guidGetAcceptExSockAddrs), &funcGetAcceptExSockAddrs_, sizeof(funcGetAcceptExSockAddrs_)) ) { ErrorSockMessage("EasyIocp::InitListenSocket: get funcGetAcceptExSockkAddrs_ failed."); assert(FALSE); } for(int i = 0; i < EASYIOCP_ACCEPT_NUM; ++i) { PostAccept(&compListen_, i); } print("EasyIocp::InitListenSocket: post %d recv.", EASYIOCP_ACCEPT_NUM); return; }
void EasyIocp::DoAccept(CompListenKey *listenKey, OVERLAPPED *ov, DWORD transBytes) { assert(listenKey != NULL); int index = listenKey->GetIndex(ov); if(index == -1) { print("EasyIocp::DoAccept: no index."); return; } //获取地址 sockaddr_in *localAddr, *remoteAddr; int locLen = sizeof(sockaddr_in), remoteLen = sizeof(sockaddr_in), inLocLen = sizeof(sockaddr_in) + 16, inRemoteLen = sizeof(sockaddr_in) + 16; EasyIocpBuffer *iocpBuffer = listenKey->GetOneBuffer(index); if(!iocpBuffer) { print("EasyIocp::DoAccept: invalid buffer, index is %d.", index); return; } iocpBuffer->AddTransBytes(transBytes); WSABUF *pBuf = iocpBuffer->GetWSABuf(); funcGetAcceptExSockAddrs_(pBuf->buf, pBuf->len - inLocLen - inRemoteLen, inLocLen, inRemoteLen, (sockaddr**)&localAddr, &locLen, (sockaddr**)&remoteAddr, &remoteLen); print("EasyIocp::DoAccept: new client from %s:%d on %s:%d.", inet_ntoa(remoteAddr->sin_addr), ntohs(remoteAddr->sin_port), inet_ntoa(localAddr->sin_addr), ntohs(localAddr->sin_port)); if(transBytes == 0) { //未接收到数据 DoAcceptWithoutData(listenKey, index, localAddr, remoteAddr); }else { //接收到数据 DoAcceptWithData(listenKey, index, iocpBuffer, localAddr, remoteAddr); } //再次投递Accept PostAccept(listenKey, index); }
void NetAcceptor::OnAccept(std::weak_ptr<NetConnection> clientObj, NetCompletionOP* bufObj) { auto con = clientObj.lock(); if (!con.get()) return; // Associate the new connection to our completion port HANDLE hrc = CreateIoCompletionPort( (HANDLE)bufObj->client, _comPort, (ULONG_PTR)con.get(), 0); if (hrc == NULL) { DebugPrint("OnAccept failed: %s", SocketGetLastErrorString().c_str()); return; } con->OnConnected(); // Re-post the AcceptEx AcceptBuffer* acceptObj = reinterpret_cast<AcceptBuffer*>(bufObj); PostAccept(acceptObj); }
int MightyTCPCompletionPortServer::acceptSocketObject() { int i=0; for(i=0; i<5; i++) { PCompletionPort_BufObj pUseBuf=AllocateBuffer(m_pListenObj,4096); InsertPendingAccept(pUseBuf); PostAccept(pUseBuf); } // 构建事件对象数组,以便在上面调用WSAWaitForMultipleEvents函数 HANDLE hWaitEvents[2 + MAX_THREAD]; int nEventCount = 0; hWaitEvents[nEventCount ++] =m_hAcceptEvent; hWaitEvents[nEventCount ++] =m_hRepostEvent; // 创建指定数量的工作线程在完成端口上处理I/O for(i=0; i<MAX_THREAD; i++) { HandleIOCompletionPortServer * pIOThread=new HandleIOCompletionPortServer(); pIOThread->start(this); pIOThread->setExecuteSignal(); m_tdPoolIndex++; hWaitEvents[nEventCount ++] =pIOThread->GetThreadHandle(); } // 下面进入无限循环,处理事件对象数组中的事件 while(TRUE) { int nIndex = ::WSAWaitForMultipleEvents(nEventCount, hWaitEvents, FALSE, 60*1000, FALSE); // 首先检查是否要停止服务 if((m_exitNotify==1) || (nIndex == WSA_WAIT_FAILED)) { // 关闭所有连接 //CloseAllConnections(); ::Sleep(0); // 给I/O工作线程一个执行的机会 // 关闭监听套节字 ::closesocket(m_ListenSock); m_ListenSock= INVALID_SOCKET; ::Sleep(0); // 给I/O工作线程一个执行的机会 // 通知所有I/O处理线程退出 for(int i=2; i<MAX_THREAD + 2; i++) { ::PostQueuedCompletionStatus(m_hCompletionPort, -1, 0, NULL); } // 等待I/O处理线程退出 /*::WaitForMultipleObjects(MAX_THREAD, &hWaitEvents[2], TRUE, 5*1000); for(i=2; i<MAX_THREAD + 2; i++) { ::CloseHandle(hWaitEvents[i]); }*/ unsigned long leftIndex,RightIndex; RightIndex=m_pThreadPool.size(); for (leftIndex=0;leftIndex<RightIndex;leftIndex++) { delete ((HandleIOCompletionPortServer *)m_pThreadPool[leftIndex]); Sleep(10); } ::CloseHandle(m_hCompletionPort); ::ExitThread(0); } //定时检查所有未返回的AcceptEx I/O的连接建立了多长时间 if(nIndex == WSA_WAIT_TIMEOUT) { CheckPostAcceptTimeOut(); } else { nIndex = nIndex - WAIT_OBJECT_0; WSANETWORKEVENTS ne; int nLimit=0; if(nIndex == 0) { ::WSAEnumNetworkEvents(m_ListenSock,hWaitEvents[nIndex], &ne); if(ne.lNetworkEvents & FD_ACCEPT) { nLimit = 50; // 增加的个数,这里设为50个 } } else if(nIndex == 1) { nLimit = InterlockedExchange(&m_nRepostCount, 0); } else if(nIndex > 1) // I/O服务线程退出,说明有错误发生,关闭服务器 { m_exitNotify=1; continue; } // 投递nLimit个AcceptEx I/O请求 int i = 0; while(i++<nLimit) { PCompletionPort_BufObj pBeforeHandBuf=AllocateBuffer(m_pListenObj,4096); if (pBeforeHandBuf!=NULL) { InsertPendingAccept(pBeforeHandBuf); PostAccept(pBeforeHandBuf); } } } } return 0; }
//--------------------------------------------------------------------------------------------------------------------------- //StartServer() //start listen //--------------------------------------------------------------------------------------------------------------------------- int CIocpServer::StartServer(const char *local_ip,const char *local_port) { if(!m_Inited) { fprintf(stderr, "Run Init() first !\n"); return -1; } SOCKET_OBJ *sockobj=NULL; HANDLE hrc; int endpointcount=0, rc, i; HANDLE event_accept; struct addrinfo *res=NULL, *ptr=NULL; #ifdef LOG_LEVEL2 printf("LOG_LEVEL2"); #else // #ifdef LOG_LEVEL1 printf("LOG_LEVEL1"); #else printf("LOG_NONE"); #endif // #endif printf("\n\n连接线程:%d: 监听线程:%d; 平均连接数:%d ; ", m_CLThreads,m_Threads,AVERAGE_CONNECTIONS); printf("IOCP版本: %s;\n",IOCP_VERSION); #ifdef ENABLE_KEEPALIVE printf("心跳检测:开启; "); #else printf("心跳检测:关闭; "); #endif printf("心跳超时:%d; 关闭延时:%d\n",KEEPALIVE_TIME,CLOSE_DELAY); res = ResolveAddress(local_ip, local_port, AF_INET, SOCK_STREAM, IPPROTO_TCP); if (res == NULL) { fprintf(stderr, "ResolveAddress failed to return any addresses!\n"); return -1; } ptr = res; if (ptr) { sockobj = GetSocketObj(INVALID_SOCKET); // create the socket sockobj->s = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); if (sockobj->s == INVALID_SOCKET) { fprintf(stderr,"socket failed: %d\n", WSAGetLastError()); return -1; } // Associate the socket and its SOCKET_OBJ to the completion port hrc = CreateIoCompletionPort((HANDLE)sockobj->s, CompletionPort, (ULONG_PTR)sockobj, 0); if (hrc == NULL) { fprintf(stderr, "CreateIoCompletionPort failed: %d\n", GetLastError()); return -1; } // bind the socket to a local address and port rc = bind(sockobj->s, ptr->ai_addr, (int)ptr->ai_addrlen); if (rc == SOCKET_ERROR) { fprintf(stderr, "bind failed: %d\n", WSAGetLastError()); return -1; } BUFFER_OBJ *acceptobj=NULL; GUID guidAcceptEx = WSAID_ACCEPTEX; GUID guidGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS; DWORD bytes; // Need to load the Winsock extension functions from each provider // -- e.g. AF_INET and AF_INET6. rc = WSAIoctl( sockobj->s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidAcceptEx, sizeof(guidAcceptEx), &lpfnAcceptEx, sizeof(lpfnAcceptEx), &bytes, NULL, NULL ); if (rc == SOCKET_ERROR) { fprintf(stderr, "WSAIoctl: SIO_GET_EXTENSION_FUNCTION_POINTER failed: %d\n", WSAGetLastError()); return -1; } rc = WSAIoctl( sockobj->s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guidGetAcceptExSockaddrs, sizeof(guidGetAcceptExSockaddrs), &lpfnGetAcceptExSockaddrs, sizeof(lpfnGetAcceptExSockaddrs), &bytes, NULL, NULL ); if (rc == SOCKET_ERROR) { fprintf(stderr, "WSAIoctl: SIO_GET_EXTENSION_FUNCTION_POINTER faled: %d\n", WSAGetLastError()); return -1; } // For TCP sockets, we need to "listen" on them rc = _(sockobj->s, 32); if (rc == SOCKET_ERROR) { fprintf(stderr, "listen failed: %d\n", WSAGetLastError()); return -1; } event_accept = CreateEvent(NULL, TRUE, FALSE, NULL); if(event_accept == NULL) { fprintf(stderr,"event_accept CreateEvent failed: %d\n",GetLastError()); return -1; } rc = WSAEventSelect(sockobj->s,event_accept,FD_ACCEPT); if (rc == SOCKET_ERROR) { fprintf(stderr, "WSAEventSelect failed: %d\n", WSAGetLastError()); return -1; } // Post the AcceptEx(s) for(i=0; i < DEFAULT_ACCEPTEX_COUNT ;i++) { acceptobj = GetBufferObj(); sockobj->recvobj = acceptobj; if(PostAccept(sockobj, acceptobj) != 0) { FreeBufferObj(acceptobj); fprintf(stderr, "PostAccept failed: %d\n", WSAGetLastError()); return -1; } } endpointcount++; ptr = ptr->ai_next; } // free the addrinfo structure for the 'bind' address freeaddrinfo(res); DWORD sleeptime = CLOSE_DELAY / 2; //每次sleep的时间 #ifdef LOG_STATUS long sock=0; long buf=0; #endif if(sleeptime < 50) //限制在50ms以外 sleeptime = 50; DWORD time_ontimer=GetTickCount(); DWORD time_close = time_ontimer; DWORD time_alive = time_ontimer; DWORD newtime; BUFFER_OBJ *acceptobj; printf("\n>>> 服务器地址: %s: 端口号: %s <<<\n\n", local_ip, local_port); while (1) { rc = WaitForSingleObject(event_accept,sleeptime); if(rc == WAIT_FAILED) { fprintf(stderr,"WaitForSingleObject Failed:%d\n",GetLastError()); break; } else if(rc != WAIT_TIMEOUT) //GOT FD_ACCEPT { // acceptobj = GetBufferObj(); // PostAccept(sockobj,acceptobj); if(m_accept_count < DEFAULT_ACCEPTEX_COUNT /2) { for(int i=0;i<DEFAULT_ACCEPTEX_COUNT/2;i++) { acceptobj = GetBufferObj(); PostAccept(sockobj,acceptobj); } } ResetEvent(event_accept); } newtime = GetTickCount(); if(newtime - time_ontimer > 3000) // 3秒 { OnTimer(); //call virtual timer(); time_ontimer = newtime; #ifdef LOG_STATUS //显示服务器状态 if(sock != gTotalSock || buf != gTotalBuf) { Log_Server.Write("服务器状态 : sock : %d ; buf : %d ; IoCount : %d ;",gTotalSock,gTotalBuf,gIoCount); sock = gTotalSock; buf = gTotalBuf; } #endif } //Check Close if(newtime - time_close > sleeptime) { time_close = newtime; CheckClose(); } if(newtime - time_alive > KEEPALIVE_TIME / 3) { CheckAlive(); time_alive = newtime; } } WSACleanup(); return 0; }
//--------------------------------------------------------------------------------------------------------------------------- //HanelIO() //--------------------------------------------------------------------------------------------------------------------------- void CIocpServer::HandleIo(SOCKET_OBJ *sock, BUFFER_OBJ *buf, HANDLE CompPort, DWORD BytesTransfered, DWORD error, ADOConn *pAdo,bool isClient) { #ifdef LOG_STATUS InterlockedDecrement(&gIoCount); #endif switch(buf->operation) { case OP_ACCEPT: //处理AcceptEx的返回 LOCK(&sock->cs);//加锁 { if(error == 0) { SOCKET_OBJ *clientobj = GetSocketObj(buf->sclient);//创建一个客户端sockobj HANDLE hrc = CreateIoCompletionPort( //将sockobj添加到完成端口处理列表 (HANDLE)buf->sclient, CompPort, (ULONG_PTR)clientobj, 0 ); if (hrc != NULL) { //读取ip地址 SOCKADDR *local=NULL; SOCKADDR *remote=NULL; int local_len; int remote_len; lpfnGetAcceptExSockaddrs(buf->buf,0,sizeof(SOCKADDR_STORAGE) + 16 ,sizeof(SOCKADDR_STORAGE) + 16, &local,&local_len,&remote,&remote_len); clientobj->addr = ((SOCKADDR_IN *)remote)->sin_addr; #ifdef LOG_LEVEL1 Log_Server.Write("--新连接 ip = %s , sock = %d ",GetAddress(clientobj), clientobj->s); #endif BUFFER_OBJ *recvobj = GetBufferObj(); //禁用发送缓冲 #ifdef SEND_BUF_DISABLE BOOL sndbuf=0; setsockopt(buf->sclient,SOL_SOCKET,SO_SNDBUF,(char *)&sndbuf,sizeof(sndbuf)); #endif LOCK(&clientobj->cs); if(PostRecv(clientobj,recvobj) == 0) { #ifdef DEBUG_IOCP clientobj->sockfd = clientobj->s; recvobj->sclient = clientobj->s; #endif clientobj->recvobj = recvobj; AddAlive(clientobj,GetTickCount()); //把他添加到心跳列表,如果一个客户端连上来以后不发数据,会被踢掉 } else { FreeBufferObj(recvobj); closesocket(clientobj->s); //注意关闭句柄,clientobj->s的句柄在PostAccept时候创建 clientobj->s = INVALID_SOCKET; FreeSocketObj(clientobj); } UNLOCK(&clientobj->cs); } else { //创建完成端口失败,像new失败一样,基本上不会出现 #ifdef LOG_LEVEL2 Log_Server.Write("CreateIoCompletionPort 错误:%d",GetLastError()); #endif closesocket(clientobj->s); clientobj->s = INVALID_SOCKET; FreeSocketObj(clientobj); } } else //如果AcceptEx返回出错,说明有一个客户端连了一半就退了,需要把他的句柄关了. closesocket(buf->sclient); InterlockedDecrement(&m_accept_count); // 一般情况下重新PostAccept if(m_accept_count < DEFAULT_ACCEPTEX_COUNT *2) { if(PostAccept(sock,buf)!=0) FreeBufferObj(buf); } } UNLOCK(&sock->cs); break; case OP_READ: //收到数据了 { LOCK(&sock->cs); //锁一下 bool bflag = false; _ASSERTE(buf == sock->recvobj); if(error == 0 && BytesTransfered > 0 ) { #ifdef LOG_LEVEL1 char head[256]; sprintf(head,"(%d) :接收",sock->s); if(isClient) strcat(head,"CL"); Log_Server.WriteHex(buf->buf+buf->buflen,BytesTransfered,head,(int)strlen(head)); #endif buf->buflen += BytesTransfered; int nret = 0; if(isClient) { //调用可以重载的虚函数 //开锁,否则在On系列函数中调用Send(),CloseSock()时候会死锁! UNLOCK(&sock->cs); nret = CLOnRead(sock,buf->buf,buf->buflen,sock->flag,pAdo); LOCK(&sock->cs); } else if(sock->flag_accept == 1) { UNLOCK(&sock->cs); nret = OnRead(sock,buf->buf,buf->buflen,pAdo); LOCK(&sock->cs); } else { sock->flag_close = 1; //设置允许标志,否则调用Send将会失败 sock->flag_accept = 1; //设置accept标志 #ifndef ENABLE_KEEPALIVE //没有启用KeepAlive DeleteAlive(sock); #endif #ifdef DEBUG_IOCP sock->freeed = 0; sock->onclosed = 0; #endif UNLOCK(&sock->cs); nret = OnAccept(sock,buf->buf,buf->buflen,pAdo); LOCK(&sock->cs); } _ASSERTE(nret >= 0 && nret <= buf->buflen); if(nret < 0 || nret > buf->buflen) { #ifdef LOG_LEVEL2 Log_Server.Write("指令处理出错啦\n"); nret = buf->buflen; //强制设置为完全处理 #endif } #ifdef ENABLE_KEEPALIVE sock->timeAlive = GetTickCount(); //设置新的心跳时间 #endif buf->buflen -= nret; if(nret > 0 && buf->buflen > 0) memmove(buf->buf,buf->buf+nret,buf->buflen); if(PostRecv(sock,buf) == 0) //重新递交一个接收操作 bflag = true; } if(!bflag) { DeleteClose(sock); //看看是否存在于延时关闭列表中 DeleteAlive(sock); //看看是否存在于心跳列表中 if(sock->s != INVALID_SOCKET) { closesocket(sock->s); sock->s = INVALID_SOCKET; } sock->flag_close = 0; //设置关闭标志 FreeBufferObj(buf); if( sock->flag_accept == 1) { UNLOCK(&sock->cs); if(!isClient) OnClose(sock,pAdo); //调用一次OnClose(),告诉上层的程序,不要再去用这个sock了 else CLOnClose(sock,sock->flag,pAdo); LOCK(&sock->cs); #ifdef DEBUG_IOCP sock->onclosed = 1; //调试时设置关闭标志,用于检测是否存在逻辑问题 #endif } sock->recvobj = NULL; if(sock->recvobj == NULL && sock->sendobj == NULL) { UNLOCK(&sock->cs); FreeSocketObj(sock); //释放该客户端对应的sockobj对象 return; } } UNLOCK(&sock->cs); } break; case OP_WRITE: LOCK(&sock->cs); { _ASSERTE(buf == sock->sendobj); bool bflag = false; BUFFER_OBJ *tmpobj = sock->sendobj; sock->sendobj = sock->sendobj->next; if(error == 0 && BytesTransfered > 0) //前一个发送已经完成 { #ifdef LOG_LEVEL1 char head[256]; sprintf(head,"(%d) :发送",sock->s); if(isClient) strcat(head,"CL"); Log_Server.WriteHex(buf->buf,BytesTransfered,head,(int)strlen(head)); #endif //检查发送队列 if(sock->sendobj == NULL) bflag = true; else if(PostSend(sock,sock->sendobj) == 0) bflag = true; } FreeBufferObj(tmpobj); if(!bflag) { sock->flag_close = 0; //设置关闭标志 while(sock->sendobj) { tmpobj = sock->sendobj; sock->sendobj = sock->sendobj->next; FreeBufferObj(tmpobj); } if(sock->recvobj == NULL && sock->sendobj == NULL) { UNLOCK(&sock->cs); FreeSocketObj(sock); //如果OP_READ时,sock->sendobj!=NULL,那么需要在这里释放客户端的SocketOBJ return; } } } UNLOCK(&sock->cs); break; } }
void main() { // 创建监听套节字,绑定到本地端口,进入监听模式 int nPort = 4567; SOCKET sListen = ::WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, //此三个参数与标准socket相同 NULL, //指定下层服务提供者,可以是NULL 0, //保留 WSA_FLAG_OVERLAPPED); //指定socket属性,要使用重叠I/O模型,必须指定WSA_FLAG_OVERLAPPED //如果使用socket则默认指定WSA_FLAG_OVERLAPPED //绑定并监听IP和端口 SOCKADDR_IN si; si.sin_family = AF_INET; si.sin_port = ::ntohs(nPort); si.sin_addr.S_un.S_addr = INADDR_ANY; ::bind(sListen, (sockaddr*)&si, sizeof(si)); ::listen(sListen, 200); // 为监听套节字创建一个SOCKET_OBJ对象 GetSocketObj函数仅仅开辟一个PSOCKET_OBJ内存并将套接字传入, PSOCKET_OBJ pListen = GetSocketObj(sListen); // 加载扩展函数AcceptEx GUID GuidAcceptEx = WSAID_ACCEPTEX; DWORD dwBytes; //套接字选项和I/O控制命令 此处用来获取AcceptEx函数指针 WSAIoctl(pListen->s, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx, sizeof(GuidAcceptEx), &pListen->lpfnAcceptEx, sizeof(pListen->lpfnAcceptEx), &dwBytes, NULL, NULL); g_pfnGetAcceptExSockaddrs = (LPFN_GETACCEPTEXSOCKADDRS)GetExtensionFuncPtr(pListen->s); // 创建用来重新建立g_events数组的事件对象 g_events[0] = ::WSACreateEvent(); // 在此可以投递多个接受I/O请求 投递5个接受连接请求 for(int i=0; i<5; i++) { PostAccept(GetBufferObj(pListen, BUFFER_SIZE)); } ::WSASetEvent(g_events[0]); while(TRUE) { int nIndex = ::WSAWaitForMultipleEvents(g_nBufferCount + 1, g_events, FALSE, WSA_INFINITE, FALSE); if(nIndex == WSA_WAIT_FAILED) { printf("WSAWaitForMultipleEvents() failed \n"); break; } nIndex = nIndex - WSA_WAIT_EVENT_0; for(int i=0; i<=nIndex; i++) { int nRet = ::WSAWaitForMultipleEvents(1, &g_events[i], TRUE, 0, FALSE); if(nRet == WSA_WAIT_TIMEOUT) continue; else { ::WSAResetEvent(g_events[i]); // 重新建立g_events数组 if(i == 0) { RebuildArray(); continue; } // 处理这个I/O PBUFFER_OBJ pBuffer = FindBufferObj(g_events[i]); if(pBuffer != NULL) { if(!HandleIO(pBuffer)) RebuildArray(); } } } } }
BOOL HandleIO(PBUFFER_OBJ pBuffer) { PSOCKET_OBJ pSocket = pBuffer->pSocket; // 从BUFFER_OBJ对象中提取SOCKET_OBJ对象指针,为的是方便引用 pSocket->nOutstandingOps --; DWORD dwTrans; //用于取得实际传输字节的数量 DWORD dwFlags; //用于取得完成状态 // 获取重叠操作结果 true 重叠操作成功 false 套接字上有错误发生 BOOL bRet = ::WSAGetOverlappedResult(pSocket->s, &pBuffer->ol, &dwTrans, FALSE, &dwFlags); if(!bRet) { // 在此套节字上有错误发生,因此,关闭套节字,移除此缓冲区对象。 // 如果没有其它抛出的I/O请求了,释放此缓冲区对象,否则,等待此套节字上的其它I/O也完成 if(pSocket->s != INVALID_SOCKET) { ::closesocket(pSocket->s); pSocket->s = INVALID_SOCKET; } if(pSocket->nOutstandingOps == 0) FreeSocketObj(pSocket); FreeBufferObj(pBuffer); return FALSE; } // 没有错误发生,处理已完成的I/O switch(pBuffer->nOperation) { case OP_ACCEPT: // 接收到一个新的连接,并接收到了对方发来的第一个封包 { // 为新客户创建一个SOCKET_OBJ对象 PSOCKET_OBJ pClient = GetSocketObj(pBuffer->sAccept); // 为收发数据创建一个BUFFER_OBJ对象,这个对象会在套节字出错或者关闭时释放 PBUFFER_OBJ pSend = GetBufferObj(pClient, BUFFER_SIZE); if(pSend == NULL) { printf(" Too much connections! \n"); FreeSocketObj(pClient); return FALSE; } SOCKADDR_IN LocalSockAddr; SOCKADDR_IN RemoteSockAddr; int nLocalLen, nRmoteLen; LPSOCKADDR pLocalAddr, pRemoteAddr; g_pfnGetAcceptExSockaddrs( pBuffer->buff, pBuffer->nLen - ((sizeof(sockaddr_in) + 16) * 2), sizeof(sockaddr_in) + 16, sizeof(sockaddr_in) + 16, (SOCKADDR **)&pLocalAddr, &nLocalLen, (SOCKADDR **)&pRemoteAddr, &nRmoteLen); memcpy(&LocalSockAddr, pLocalAddr, nLocalLen); memcpy(&RemoteSockAddr, pRemoteAddr, nRmoteLen); printf("Local Accepted client:%s:%d\n", inet_ntoa(LocalSockAddr.sin_addr), ntohs(LocalSockAddr.sin_port)); printf("Remote Accepted client:%s:%d\n", inet_ntoa(RemoteSockAddr.sin_addr), ntohs(RemoteSockAddr.sin_port)); RebuildArray(); // 将数据复制到发送缓冲区 pSend->nLen = dwTrans; memcpy(pSend->buff, pBuffer->buff, dwTrans); // 投递此发送I/O(将数据回显给客户) if(!PostSend(pSend)) { // 万一出错的话,释放上面刚申请的两个对象 FreeSocketObj(pSocket); FreeBufferObj(pSend); return FALSE; } // 继续投递接受I/O PostAccept(pBuffer); } break; case OP_RECV: // 接收数据完成 { if(dwTrans > 0) { // 创建一个缓冲区,以发送数据。这里就使用原来的缓冲区 PBUFFER_OBJ pSend = pBuffer; printf("收到:%s\r\n", pBuffer->buff); pSend->nLen = dwTrans; // 投递发送I/O(将数据回显给客户) PostSend(pSend); } else // 套节字关闭 { // 必须先关闭套节字,以便在此套节字上投递的其它I/O也返回 if(pSocket->s != INVALID_SOCKET) { ::closesocket(pSocket->s); pSocket->s = INVALID_SOCKET; } if(pSocket->nOutstandingOps == 0) FreeSocketObj(pSocket); FreeBufferObj(pBuffer); return FALSE; } } break; case OP_SEND: // 发送数据完成 { if(dwTrans > 0) { // 继续使用这个缓冲区投递接收数据的请求 pBuffer->nLen = BUFFER_SIZE; PostRecv(pBuffer); } else // 套节字关闭 { // 同样,要先关闭套节字 if(pSocket->s != INVALID_SOCKET) { ::closesocket(pSocket->s); pSocket->s = INVALID_SOCKET; } if(pSocket->nOutstandingOps == 0) FreeSocketObj(pSocket); FreeBufferObj(pBuffer); return FALSE; } } break; } return TRUE; }