Follow these steps to complete the port model:
1. Call the createiocompletionport function to create the port.
HANDLE CompletionPort=CreateIoCompletionStatus(INVALID_HANDLE_VALUE,NULL,0,0);
2. Create a worker thread with the same number of processors
SYSTEM_INFO SysInfo;GetSystemInfo(&SysInfo);for(int i=0;i<SysInfo.)for(int i=0;i<(sysInfo.dwNumberOfProcessors);i++){ HANDLE ThreadHandle=(HANDLE)_beginthreadex(NULL,0,CompletionPortProcessor,ComplPort,0,NULL); CloseHandle(ThreadHandle);}
3. Accept the client connection request, create a single handle data, and call createiocompletionport to bind the client socket to the completion port.
You can define fields for the data structure of the document handle:
struct PTR_HANDLE_DATA{//字段可以随意定义 SOCKET s; int i;}
Bind the socket to the completion port:
CreateIoCompletionPort(sClient,CompletionPort,(DWORD)PerHandleData,0);
4. Create a single I/O data and pass the single I/O data as parameters to overlapping I/O functions: wsarecv and wsasend.
Create a single I/O data. Except that the first field must be overlapped, other fields can be defined as follows:
<pre class="cpp" name="code">struct PER_IO_DATA{OVERLAPPED Overlapped;WSABUF DataBuf;char Buffer[DATA_BUFFER];int OperationType;};
Call overlapping I/O functions:
WSARecv(PerHandleData->socket, &PerIoData->DataBuf, 1, &dwRecv, &Flags, &PerIoData->Overlapped, NULL);
5. In the working thread, call the getqueuedcompletionstatus function to wait for the completion request of the port.
GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (LPDWORD)&PerHandleData, (LPOVERLAPPED*)&PerIoData, INFINITE))
6. Wait until the request is processed successfully. If you need to deliver an overlapping I/O again.
A simple example is as follows:
#include <WinSock2.h>#include <stdio.h>#include <string.h>#include <ws2tcpip.h>#include <process.h>#pragma comment(lib, "ws2_32.lib ") //linking to the library #define DATA_BUFFER 4*1024#define RECV_OPERATION1#define SEND_OPERATION 2struct PTR_HANDLE_DATA{SOCKET socket;int Location;};struct PER_IO_DATA{OVERLAPPED Overlapped;WSABUF DataBuf;char Buffer[DATA_BUFFER];int OperationType;};unsigned int WINAPI CompletionPortProcessor(PVOID lParam){ HANDLE CompletionPort = (HANDLE)lParam; DWORD BytesTransferred; PTR_HANDLE_DATA *PerHandleData; PER_IO_DATA *PerIoData; while(true) { if(0 == GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (LPDWORD)&PerHandleData, (LPOVERLAPPED*)&PerIoData, INFINITE)) { if( (GetLastError() == WAIT_TIMEOUT) || (GetLastError() == ERROR_NETNAME_DELETED) ) {closesocket(PerHandleData->socket); delete PerIoData; delete PerHandleData; continue; } return 0; } // 说明客户端已经退出 if(BytesTransferred == 0) { closesocket(PerHandleData->socket); delete PerIoData; delete PerHandleData; continue; }if(PerIoData->OperationType==RECV_OPERATION){printf("%d:%s\n",PerHandleData->Location,PerIoData->DataBuf.buf);// 继续向 socket 投递WSARecv操作DWORD Flags = 0;DWORD dwRecv = 0;ZeroMemory(PerIoData, sizeof(PER_IO_DATA));PerIoData->DataBuf.buf = PerIoData->Buffer;PerIoData->DataBuf.len = DATA_BUFFER;PerIoData->OperationType=RECV_OPERATION;WSARecv(PerHandleData->socket, &PerIoData->DataBuf, 1, &dwRecv, &Flags, &PerIoData->Overlapped, NULL); } } return 0;}void main(){HANDLE ComplPort;ComplPort=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);SYSTEM_INFO sysInfo;memset(&sysInfo,0,sizeof(sysInfo));GetSystemInfo(&sysInfo);HANDLE *handleArray=(HANDLE *)malloc(sysInfo.dwNumberOfProcessors *sizeof(HANDLE));for(int i=0;i<(sysInfo.dwNumberOfProcessors);i++){handleArray[i]=(HANDLE)_beginthreadex(NULL,0,CompletionPortProcessor,ComplPort,0,NULL);}WSADATA wsaData;WSAStartup(MAKEWORD(2,2),&wsaData);SOCKET s,sClient;struct addrinfo hints,*result;int rc;memset(&hints,0,sizeof(hints));hints.ai_flags=AI_NUMERICHOST;//nodename is ip address;if set AI_PASSIVE ,it is computer name;if set AI_CANONNAME ,it is ..hints.ai_family=AF_UNSPEC;//IPv4 OR IPv6;if IPv4,Set AF_INET; if IPv6,Set AF_INET6hints.ai_socktype=SOCK_STREAM;//SOCK_DRGAMhints.ai_protocol=IPPROTO_TCP;rc=getaddrinfo("127.0.0.1","5001",&hints,&result);s=socket(result->ai_family,result->ai_socktype,result->ai_protocol);bind(s,result->ai_addr,result->ai_addrlen);listen(s,5);PER_IO_DATA *PerIoData;PTR_HANDLE_DATA *PerHandleData;int i=1; while(true) { sClient = accept(s, 0,0); PerHandleData = new PTR_HANDLE_DATA();PerHandleData->socket = sClient;PerHandleData->Location=i; CreateIoCompletionPort((HANDLE)PerHandleData->socket, ComplPort, (DWORD)PerHandleData, 0); PerIoData = new PER_IO_DATA(); ZeroMemory(PerIoData, sizeof(PER_IO_DATA)); PerIoData->DataBuf.buf = PerIoData->Buffer; PerIoData->DataBuf.len =DATA_BUFFER;PerIoData->OperationType=RECV_OPERATION; DWORD Flags = 0; DWORD dwRecv = 0; WSARecv(PerHandleData->socket, &PerIoData->DataBuf, 1, &dwRecv, &Flags, &PerIoData->Overlapped, NULL);i++; } DWORD dwByteTrans; PostQueuedCompletionStatus(ComplPort, dwByteTrans, 0, 0); closesocket(s);}
Complete the port model