//--------------------------------------------------------------------------------------------------------------------------- //CLConnect() //NULL - connect failed . //--------------------------------------------------------------------------------------------------------------------------- SOCKET_OBJ * CIocpServer::CLConnect(const char * ip,const char *port,int flag) { SOCKET_OBJ *sockobj = NULL; BUFFER_OBJ *recvobj = NULL; struct addrinfo *res=NULL; bool bFlag = false; res = ResolveAddress(ip, port, AF_INET,SOCK_STREAM, IPPROTO_TCP); if (res == NULL) { fprintf(stderr, "CLConnect ResolveAddress failed to return any addresses!\n"); return NULL; } sockobj = GetSocketObj(INVALID_SOCKET); // create the socket sockobj->s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sockobj->s == INVALID_SOCKET) { fprintf(stderr,"CLConnect socket failed: %d\n", WSAGetLastError()); FreeSocketObj(sockobj); return NULL; } #ifdef ENABLE_UNLIMIT_PORT SOCKADDR_IN local_addr={0}; local_addr.sin_family = AF_INET; local_addr.sin_addr.s_addr = ADDR_ANY; BOOL optvar = true; for(int i=0;i<40;i++) { local_addr.sin_port = htons(m_UnlimitPort); setsockopt(sockobj->s,SOL_SOCKET,SO_REUSEADDR,(char*)&optvar,sizeof(optvar)); if(bind(sockobj->s,(SOCKADDR *)&local_addr,sizeof(SOCKADDR)) == -1) { if(m_UnlimitPort < UNLIMIT_PORT_END) m_UnlimitPort++; else m_UnlimitPort = UNLIMIT_PORT_START; if(WSAGetLastError() != WSAEADDRINUSE ) { //bind出错了 fprintf(stderr,"bind() failed: %d\n", WSAGetLastError()); closesocket(sockobj->s); sockobj->s = INVALID_SOCKET; FreeSocketObj(sockobj); return NULL; } } else break; } if(m_UnlimitPort < UNLIMIT_PORT_END) m_UnlimitPort++; else m_UnlimitPort = UNLIMIT_PORT_START; #endif if( connect(sockobj->s,res->ai_addr,(int)res->ai_addrlen)!=SOCKET_ERROR ) { if( CreateIoCompletionPort((HANDLE)sockobj->s, CLCompletionPort, (ULONG_PTR)sockobj, 0) == NULL) fprintf(stderr, "CLConnect : CLCreateIoCompletionPort failed: %d\n", GetLastError()); else bFlag = true; } #ifdef LOG_LEVEL2 if(!bFlag) Log_Server.Write("CLConnect失败: %d\n",WSAGetLastError()); #endif if(bFlag) { recvobj = GetBufferObj(); #ifdef DEBUG_IOCP recvobj->sclient = sockobj->s; #endif LOCK(&sockobj->cs); if (PostRecv(sockobj, recvobj) != NO_ERROR) { UNLOCK(&sockobj->cs); FreeBufferObj(recvobj); } else { sockobj->flag = flag; sockobj->flag_accept = 1; sockobj->flag_close = 1; sockobj->recvobj = recvobj; #ifdef ENABLE_KEEPALIVE AddAlive(sockobj,GetTickCount()); #endif #ifdef DEBUG_IOCP sockobj->freeed = 0; sockobj->onclosed = 0; #endif UNLOCK(&sockobj->cs); CLOnConnect(sockobj,sockobj->flag); return sockobj; } } closesocket(sockobj->s); sockobj->s = INVALID_SOCKET; FreeSocketObj(sockobj); return NULL; }
// // Function: HandleIo // // Description: // This function handles the IO on a socket. First, the events signaled // on the socket are enuemrated, then the appropriate handler routine // for the event is called. // int HandleIo(THREAD_OBJ *thread, SOCKET_OBJ *sock) { WSANETWORKEVENTS nevents; int rc; // Enumerate the events rc = WSAEnumNetworkEvents( sock->s, sock->event, &nevents ); if (rc == SOCKET_ERROR) { fprintf(stderr, "HandleIo: WSAEnumNetworkEvents failed: %d\n", WSAGetLastError()); return SOCKET_ERROR; } if (nevents.lNetworkEvents & FD_READ) { // Check for read error if (nevents.iErrorCode[FD_READ_BIT] == 0) { rc = ReceivePendingData(sock); if (rc == -1) { RemoveSocketObj(thread, sock); FreeSocketObj(sock); return SOCKET_ERROR; } rc = SendPendingData(sock); if (rc == -1) { RemoveSocketObj(thread, sock); FreeSocketObj(sock); return SOCKET_ERROR; } } else { fprintf(stderr, "HandleIo: FD_READ error %d\n", nevents.iErrorCode[FD_READ_BIT]); RemoveSocketObj(thread, sock); FreeSocketObj(sock); return SOCKET_ERROR; } } if (nevents.lNetworkEvents & FD_WRITE) { // Check for write error if (nevents.iErrorCode[FD_WRITE_BIT] == 0) { rc = SendPendingData(sock); if (rc == -1) { RemoveSocketObj(thread, sock); FreeSocketObj(sock); return SOCKET_ERROR; } } else { fprintf(stderr, "HandleIo: FD_WRITE error %d\n", nevents.iErrorCode[FD_WRITE_BIT]); return SOCKET_ERROR; } } if (nevents.lNetworkEvents & FD_CLOSE) { // Check for close error if (nevents.iErrorCode[FD_CLOSE_BIT] == 0) { // Socket has been indicated as closing so make sure all the data // has been read while (1) { rc = ReceivePendingData(sock); if (rc == -1) { RemoveSocketObj(thread, sock); FreeSocketObj(sock); return SOCKET_ERROR; } else if (rc != 0) { continue; } else { break; } } // See if there is any data pending, if so try to send it rc = SendPendingData(sock); if (rc == -1) { RemoveSocketObj(thread, sock); FreeSocketObj(sock); return SOCKET_ERROR; } } else { fprintf(stderr, "HandleIo: FD_CLOSE error %d\n", nevents.iErrorCode[FD_CLOSE_BIT]); RemoveSocketObj(thread, sock); FreeSocketObj(sock); return SOCKET_ERROR; } } return NO_ERROR; }
//--------------------------------------------------------------------------------------------------------------------------- //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; } }
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; }