主线程创建监听套接字,创建额外工作线程,关联IOCP,负责等待和接受到来的连接。
调用GetQueuedCompletionStatus函数,函数返回:
1 调用失败
2 套接字被对方关闭
3 请求成功完成
程序首先定义per-handle per-IO的操作数据的结构类型
#define BUFFER_SIZE 1024 typedef struct _PER_HANDLE_DATA{ SOCKET s; sockaddr_in addr; }PER_HANDLE_DATA,*PPER_HANDLE_DATA; typedef struct _PER_IO_DATA{ OVERLAPPED ol; char buf[BUFFER_SIZE]; int nOperationType; #define OP_READ 1 #define OP_WRITE 2 #define OP_ACCEPT 3 }PER_IO_DATA,*PPER_IO_DATA;
主要过程:
1 主线程创建完成端口对象,创建工作线程处理完成端口对象中的事件
2 创建监听套接字,开始监听服务器端口
3 进入无限循环,处理到来的请求
1)调用accept函数等待接受未决的连接请求 2)创建一个per-handle数据 3)投递一个接收请求
实现代码:
void main() { int nPort = 4567; HANDLE hCompletion = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE,0,0,0); ::CreateThread(NULL,0,ServerThread,(LPVOID)hCompletion,0,0); SOCKET sListen = ::socket(AF_INET,SOCK_STREAM,0); SOCKADDR_IN si; si.sin_family = AF_INET; si.sin_port = htons(nPort); si.sin_addr.S_un.S_addr = INADDR_ANY; ::bind(sListen,(sockaddr*)&si,sizeof(si)); ::listen(sListen,5); while(TRUE){ //等待接收未决的请求 SOCKADDR_IN saRemote; int nRemoteLen = sizeof(saRemote); SOCKET sNew = ::accept(sListen,(sockaddr*)&saRemote,&nRemoteLen); //创建per-handle PPER_HANDLE_DATA pPerHandle = (PPER_HANDLE_DATA)::GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA)); pPerHandle->s = sNew; memcpy(&pPerHandle->addr,&saRemote,nRemoteLen); ::CreateIoCompletionPort((HANDLE)pPerHandle->s,hCompletion,(DWORD)pPerHandle,0); //投递一个接收请求 PPER_IO_DATA pPerIO = (PPER_IO_DATA)::GlobalAlloc(GPTR,sizeof(PER_IO_DATA)); pPerIO->nOperationType = OP_READ; WSABUF buf; buf.buf = pPerIO->buf; buf.len = BUFFER_SIZE; DWORD dwRecv; DWORD dwFlags = 0; ::WSARecv(pPerHandle->s,&buf,1,&dwRecv,&dwFlags,&pPerIO->ol,NULL);//接收投递求 } } DWORD WINAPI ServerThread(LPVOID lpParam{ HANDLE hCompletion = (HANDLE)lpParam; DWORD dwTrans; PPER_HANDLE_DATA pPerHandle; PPER_IO_DATA pPerIO; while(TRUE){ BOOL bOK = ::GetQueuedCompletionStatus(hCompletion,&dwTrans,(LPDWORD)&pPerHandle,(LPOVERLAPPED*)&pPerIO,WSA_INFINITE); if(!bOK) { ::closesocket(pPerHandle->s); ::GlobalFree(pPerHandle); ::GlobalFree(pPerIO); continue; } if(dwTrans == 0 && (pPerIO->nOperationType==OP_READ||pPerIO->nOperationType==OP_WRITE)) { ::closesocket(pPerHandle->s); ::GlobalFree(pPerHandle); ::GlobalFree(pPerIO); continue; } switch(pPerIO->nOperationType) { case OP_READ: { pPerIO->buf[dwTrans] = '\0'; printf(pPerIO->buf); WSABUF buf; buf.buf = pPerIO->buf; buf.len = BUFFER_SIZE; pPerIO->nOperationType = OP_READ; DWORD nFlags = 0; ::WSARecv(pPerHandle->s,&buf,1,&dwTrans,&nFlags,&pPerIO->ol,NULL); } break; case OP_WRITE: case OP_ACCEPT: break; } } return 0; }