主线程创建监听套接字,创建额外工作线程,关联IOCP,负责等待和接受到来的连接。
调用GetQueuedCompletionStatus函数,函数返回:
1 调用失败
2 套接字被对方关闭
3 请求成功完成
程序首先定义per-handle per-IO的操作数据的结构类型
代码语言:javascript复制#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)投递一个接收请求
实现代码:
代码语言:javascript复制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] = '