Tag:完成端口 基于完成端口的服务器端模型 一:初始化套接字服务 WSAStartup() 二:创建完成端口 完成端口=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,工作线程数量); 三:创建指定数量的工作线程,运行它们,并在GetQueuedCompletionStatus调用中等待。 CreateThread(NULL,0,WorkThread,this,0,NULL); 四:创建监听套接字 监听套接字=WSASocket(AF_INET,SOCK_STREAM,0, NULL,0,WSA_FLAG_OVERLAPPED) 五:绑定,监听 bind(监听套接字, (PSOCKADDR) &addr, sizeof(addr); listen(监听套接字, 10) 六:创建监听线程 CreateThread(NULL,0,OnAccept,this,0,&dwThreadId); 创建完成端口其实是建立I/O投递的队列 监听线程中把完成端口与当前的客户端会话套接字绑定,这样此客户端会话的I/O信息就可以通过此完成端口进入投递队列,与此同时各个工作线程一直在调用GetQueuedCompletionStatus获取队列中的完成状态,一旦队列中有I/O投递,则当前工作线程就处理它,处理完成后,重新调用返回循环,继续调用GetQueuedCompletionStatus,处理各个客户端的下个投递请求。 监听线程把完成端口与当前的客户端会话套接字绑定后,则返回继续监听下个客户端的连接请求。 监听线程流程伪代码 while(1) { SOCKET 客户端会话套接字; //堵塞调用,直到有客户连接上来 客户端会话套接字=WSAAccept(监听套接字, NULL, NULL, NULL, 0); //把此客户端会话套接字绑定到完成端口,为重叠I/O数据结构分配内存 LPPER_HANDLE_DATA PerHandleData; CreateIoCompletionPort((HANDLE*)客户端会话套接字, 完成端口, (DWORD)PerHandleData, 0); //读取客户端首次数据 WSARecv(socket, &(PerHandleData->pIOContext->DataBuf), 1, &RecvBytes, &Flags, &(PerHandleData->pIOContext->Overlapped), NULL) //以上处理好后,某个工作线程中调用GetQueuedCompletionStatus即可成功, 工作线程进入工作状态。 } 工作线程流程伪代码 while(1) { //等待客户端I/O投递 bSuccess=GetQueuedCompletionStatus(完成端口, &dwNumBytes, //数据长度 (DWORD*)&PerHandleData, //自定义结构 (OVERLAPPED**)&ConText, //重叠结构 INFINITE); if(!bSuccess) { //客户端断开连接 if(PerHandleData!=NULL) { if(dwNumBytes == 0 && PerHandleData->pIOContext->OperationType==RECV_POST) { pThis->CloseClient(PerHandleData); } } } else { if(PerHandleData==NULL && dwNumBytes==0) { //工作线程被通知结束 SetEvent(g_ThreadHandles[pos]); return 0; } //数据处理 dwRet=pThis->ProcessJob(PerHandleData->Socket, ConText,dwNumBytes); if(dwRet==PROCESS_UNRECOGNIZED) { pThis->CloseClient(PerHandleData); continue; } if(dwRet==PROCESS_FAIL) return 0; } }

评论