1.API函数
1).创建I/O完成端口对象
HANDLE CreateIoCompletionPort(
HANDLE FileHandle,
HANDLE ExistingCompletionPort,
DWORD CompletionKey,
DWORD NumberOfConcurrentThreads
);
说明:FileHandle指定一个同完成端口关联在一起的套接字句柄;ExistingcompletionProt指定是一个现在有的完成端口;CompletionKey指定要与某个特定套接字句柄关联在一起的“单句柄数据”
2)获取排队完成状态
BOOL GetQueuedCompletionStatus(
HANDLE CompletionProt,
LPDWORD lpNumberOfBytesTransferred,
LPDWORD lpCompletionKey,
LPOVERLAPPED * lpOverlapped,
DWORD dwMilliseconds
);
2.步骤&伪代码
1)创建一个完成端口,第四个参数保持为0,指定在完成端口上,每个处理器一次只允许执行一个工作线程。
2)判断系统内到底安装了多少个处理其。
3)创建工作者线程,根据步骤2)得到的处理器信息,在完成端口上,为已完成的I/O请求提供服务。
4)准备好一个监听套接字,监听进入的连接请求。
5)使用accept函数,接收进入的连接请求。
6)创建一个数据结构,用于容纳“单句柄数据”,同时在结构中存入接收的套接字句柄。
7)调用CreateIoCompletionPort,将自accept返回的新套接字句柄同完成端口关联到一起。通过CompletionKey将单句柄数据结构传递给CreateIoCompletionPort。
8)开始在已接收的连接上进行I/O操作。
9)重复步骤5)~8)。
示例:
StartWinsock();
//Step 1:
//Create an I/O Completion port
CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
//Step 2:
GetSystemInfo(&SystemInfo);
//Step3
for(i = 0; i< SystemInfo.dwNumberOfProcessors; i++)
{
HANDLE ThreadHandle;
//NOTE: the ServerWorkerThread procedure is not defined
//in this listing.
ThreadHandle = CreateThread(NULL,0,ServerWorkerThread,CompletionPort,0,&ThreadID);
CloseHandle(ThreadHandle);
}
//Step4
Listen = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htoml(INADDR_ANY);
InternetAddr.sin_port = htonl(5000);
bind(Listen,(SOCKADDR)&InternetAddr,sizeof(InternetAddr));
listen(Listen,5);
while(TRUE)
{
//Step 5:
Accept = WSAAccept(Listen,NULL,NULL,NULL,0);
//Step 6:
//Create per-handle data information structure to
//associate with the socket
PerHandleData = (LPPER_HANDLE_DATA)
GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA));
//Socket connected
PerHandleData->Socket = Accept;
//Step 7:
CreateIoCompletionPort((HANDLE)Accept,CompletionPort,(DWORD)PerHandleData,0);
//Step 8:
//Start processing I/O on the accepted socket.
//Post one or more WSASend() or WSARecv()calls
//on the socket using overlapped I/O
WSARecv(...);
}
//---------------------------------------------------------------
DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID)
{
HANDLE CompletionPort = (HANDLE)CompletionPortID;
DWORD BytesTransferred;
LPOVERLAPPED Overlapped;
LPPER_HANDLE_DATA PerHandleData;
DWORD SendBytes,RecvBytes;
DWORD Flags;
while(TRUE)
{
GetQueuedCompletionStatus(CompletionPort,
&BytesTransferred,(LPDWORD)*PerHandleData,
(LPOVERLAPPED *)&PerIoData,INFINITE);
if(BytesTransferred == 0 &&
(PerIoData->OperationType == RECV_POSTED ||
PerIoData->OperationType == SEND_POSTED))
{
//socket has been closed by the peer
closesocket(PerHandleData->Socket);
GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
}
if(PerIoData->OperationType == RECV_POSTED)
{
//Do something with the received data
//in PerIoData->Buffer
}
//Post another WSASend or WSARecv Operation.
Flags = 0;
ZeroMemory(&(PerIoData->Overlapped),sizeof(OVERLAPPED));
PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;
PerIoData->OperationType = RECV_POSTED;
WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &RecvBytes,&Flags,&(PerIoData->Overlapped),NULL);
}
}