windows 完成端口模型服务端
#include<iostream> #include<winsock2.h> #pragma comment(lib,"WS2_32.lib") using namespace std; const int ServerPort=4399; const int MSGSIZE=1024; typedef enum { RECV_POST, SEND_POST }OPERATION_TYPE; typedef struct { WSAOVERLAPPED wsaOverlapped; WSABUF wsaBuffer; char dataBuffer[MSGSIZE]; DWORD recvedDataSize; DWORD flags; OPERATION_TYPE operationType; }COM_IO_OPERATION_DATA,*PIO_OPERATION_DATA; typedef struct _completionKey { SOCKET sock; SOCKADDR_IN sockAddr; }COMPLETION_KEY,*PCOMPLITON_KEY; int LoadSocketLib() { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { return -1; } if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { WSACleanup( ); return -1; } return 0; } DWORD WINAPI HandleThread(LPVOID completionPortID); BOOL AsyncRecvData(SOCKET clientSOCK); int main() { system("color 2f"); //加载套接字库 if(LoadSocketLib()!=0) { cout<<"Load winsock failed"<<endl; return -1; } //创建完成端口 HANDLE completionPort=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0); if(completionPort==NULL) { cout<<"创建完成端口失败"<<endl; return -1; } SYSTEM_INFO systemInfo; GetSystemInfo(&systemInfo); DWORD dw_ThreadId;//线程ID //创建线程池 for(int i=0;i<systemInfo.dwNumberOfProcessors;i++) { CreateThread(NULL,0,HandleThread,completionPort,0,&dw_ThreadId); } //创建套接字、绑定、设为监听状态 SOCKET serverSock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(serverSock==INVALID_SOCKET) { cout<<"create socket failed"<<endl; return -1; } SOCKADDR_IN serverAddr; serverAddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY); serverAddr.sin_family=AF_INET; serverAddr.sin_port=htons(ServerPort); if(SOCKET_ERROR==bind(serverSock,(SOCKADDR*)&serverAddr,sizeof(SOCKADDR_IN))) { cout<<"binding failed"<<endl; return -1; } if(SOCKET_ERROR==listen(serverSock,5)) { cout<<"listen failed"<<endl; return -1; } //接受客户端连接请求,并关联到完成端口 SOCKADDR_IN clientAddr; int addrSize=sizeof(SOCKADDR_IN); // PIO_OPERATION_DATA lpper_IO_Data=NULL; cout<<"/t/t/t"<<"...Server begin..."<<endl; PCOMPLITON_KEY pCompletion=NULL; while(1) { SOCKET clientSock=accept(serverSock,(SOCKADDR*)&clientAddr,&addrSize); if(clientSock==INVALID_SOCKET) { closesocket(clientSock); continue; } //pCompletion=(PCOMPLITON_KEY)malloc(sizeof(COMPLETION_KEY)); // pCompletion->sock=clientSock; //pCompletion->sockAddr=clientAddr; cout<<"the client addr is..."<<inet_ntoa(clientAddr.sin_addr)<<"/t"<<ntohs(clientAddr.sin_port)<<endl; if(NULL==CreateIoCompletionPort((HANDLE)clientSock,completionPort,/*(DWORD)pCompletion*/(DWORD)clientSock,0)) { cout<<"套接字关联失败"<<endl; closesocket(clientSock); continue; } AsyncRecvData(clientSock);//发起异步接受操作 } PostQueuedCompletionStatus(completionPort,0xFFFFFFFF,0,NULL); CloseHandle(completionPort); closesocket(serverSock); WSACleanup(); return 0; } BOOL AsyncRecvData(SOCKET clientSock) { PIO_OPERATION_DATA lpper_IO_Data=NULL; lpper_IO_Data=(PIO_OPERATION_DATA)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(PIO_OPERATION_DATA));//从堆中分配内存块给关联结构体 if(lpper_IO_Data==NULL) { cout<<"allocate failed"<<endl; closesocket(clientSock); //continue; return false; } ZeroMemory(&lpper_IO_Data->wsaOverlapped,sizeof(lpper_IO_Data->wsaOverlapped)); lpper_IO_Data->wsaBuffer.len=MSGSIZE; lpper_IO_Data->wsaBuffer.buf=lpper_IO_Data->dataBuffer; lpper_IO_Data->operationType=RECV_POST; //异步调用,因此当服务器刚开启的时候第一次激发异步接受Recv会失败, if(SOCKET_ERROR==WSARecv(clientSock,&(lpper_IO_Data->wsaBuffer),1,&lpper_IO_Data->recvedDataSize,&lpper_IO_Data->flags,&lpper_IO_Data->wsaOverlapped,NULL)) { if(WSAGetLastError()!=ERROR_IO_PENDING) { cout<<"WSARecv 函数调用失败"<<WSAGetLastError<<endl;//71A23CCE closesocket(clientSock); } } return true; } DWORD WINAPI HandleThread(LPVOID completionPortID) { HANDLE completionPort=(HANDLE)completionPortID; DWORD dwBytesTransferred; SOCKET clientSock; PIO_OPERATION_DATA lp_IO_Data=NULL; //从队列中取出活跃套接字 GetQueuedCompletionStatus(completionPort,&dwBytesTransferred,(unsigned long*)&clientSock,(LPWSAOVERLAPPED*)&lp_IO_Data,INFINITE); if(dwBytesTransferred==0xFFFFFFFF) {//没有活跃套接字 return 0; } if(lp_IO_Data->operationType==RECV_POST) { if(dwBytesTransferred==0) {//客户端关闭 cout<<"客户端关闭"<<endl; closesocket(clientSock); HeapFree(GetProcessHeap(),0,lp_IO_Data); } else {//处理客户端请求 lp_IO_Data->dataBuffer[dwBytesTransferred]='/0'; //send(clientSock,lp_IO_Data->dataBuffer,dwBytesTransferred,0); WSASend(clientSock,&lp_IO_Data->wsaBuffer,1,&lp_IO_Data->recvedDataSize,lp_IO_Data->flags,&lp_IO_Data->wsaOverlapped,NULL); memset(lp_IO_Data,0,sizeof(COM_IO_OPERATION_DATA)); lp_IO_Data->wsaBuffer.buf=lp_IO_Data->dataBuffer; lp_IO_Data->wsaBuffer.len=MSGSIZE; lp_IO_Data->operationType=RECV_POST; WSARecv(clientSock,&lp_IO_Data->wsaBuffer,1,&lp_IO_Data->recvedDataSize,&lp_IO_Data->flags,&lp_IO_Data->wsaOverlapped,NULL); } } return 0; }