下面是使用Completion Port的一个简单的例子:
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
#define LISTEN_PORT 5080
#define DATA_BUFSIZE 512
typedef struct
{
WSAOVERLAPPED wsaOverlapped;
WSABUF wsaBuf;
char buffer[DATA_BUFSIZE];
}PER_IO_OPERATION_DATA, *LPPER_IO_OPERATION_DATA;
typedef struct
{
SOCKET sock;
}PER_HANDLE_DATA, *LPPER_HANDLE_DATA;
DWORD WINAPI ServerWorkerThread(LPVOID lpCompletionPortID);
int main()
{
WSADATA wsaData;
int nRet;
HANDLE hCompletionPort;
SYSTEM_INFO systemInfo;
int i;
HANDLE hThread;
DWORD dwThreadID;
SOCKET sockListen;
SOCKADDR_IN listenAddr;
SOCKET acceptSock;
LPPER_HANDLE_DATA perHandleData;
LPPER_IO_OPERATION_DATA lpPerIoOperationData;
DWORD dwFlags;
DWORD dwBytesRecv;
nRet = WSAStartup(MAKEWORD(2,2), &wsaData);
if(nRet != 0)
{
printf("WSAStartup() failed error:%d\n", nRet);
return 1;
}
else
printf("WSAStartup is OK!\n");
if((hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0)) == NULL)
{
printf("CreateIoCompletionPort() failed with error %d.\n", GetLastError());
WSACleanup();
return 1;
}
else
{
printf("CreateIoCompletionPort() is OK.\n");
}
GetSystemInfo(&systemInfo);
for(i = 0; i < (int)systemInfo.dwNumberOfProcessors*2; ++i)
{
if((hThread = CreateThread(NULL, 0, ServerWorkerThread, hCompletionPort, 0, &dwThreadID)) == NULL)
{
printf("CreateThread() failed with error %d.\n", GetLastError());
WSACleanup();
return 1;
}
else
printf("CreateThread() is OK! Thread ID:%d\n", dwThreadID);
CloseHandle(hThread);
}
if((sockListen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("WSASocket() failed with error %d.\n", WSAGetLastError());
WSACleanup();
return 1;
}
else
{
printf("WSASocket() is OK!\n");
}
listenAddr.sin_family = AF_INET;
listenAddr.sin_addr.s_addr = htonl(INADDR_ANY);
listenAddr.sin_port = htons(LISTEN_PORT);
if(bind(sockListen, (SOCKADDR*)&listenAddr, sizeof(listenAddr)) == SOCKET_ERROR)
{
printf("bind() failed, error:%d.\n", WSAGetLastError());
closesocket(sockListen);
WSACleanup();
return 1;
}
else
printf("bind()is fine!\n");
if(listen(sockListen, 5) == SOCKET_ERROR)
{
printf("listen() failed, error:%d.\n", WSAGetLastError());
closesocket(sockListen);
WSACleanup();
return 1;
}
else
{
printf("listen() is OK!");
}
while(TRUE)
{
if((acceptSock = WSAAccept(sockListen, NULL, NULL, NULL, 0)) == SOCKET_ERROR)
{
printf("WSAAccept() failed, error:%d.\n", WSAGetLastError());
WSACleanup();
return 1;
}
else
{
printf("WSAAccept() is OK!.\n");
}
if((perHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA))) == NULL)
{
printf("GlobalAlloc() failed, error:%d.\n", GetLastError());
WSACleanup();
return 1;
}
else
{
printf("GlobalAlloc() for PER_HANDLE_DATA is OK!.\n");
}
printf("socket %d create.\n", acceptSock);
perHandleData->sock = acceptSock;
if(CreateIoCompletionPort((HANDLE)acceptSock, hCompletionPort, (DWORD)perHandleData, 0) == NULL)
{
printf("CreateIoCompletionPort() failed, error:%d.\n", GetLastError());
return 1;
}
else
{
printf("CreateIoCompletionPort() is OK!.\n");
}
if((lpPerIoOperationData = (LPPER_IO_OPERATION_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_OPERATION_DATA))) == NULL)
{
printf("GlobalAlloc() failed, error:%d.\n", GetLastError());
return 1;
}
else
{
printf("GlobalAlloc() for PER_IO_OPERATION_DATA is OK!\n");
}
ZeroMemory(&(lpPerIoOperationData->wsaOverlapped), sizeof(OVERLAPPED));
lpPerIoOperationData->wsaBuf.len = DATA_BUFSIZE;
lpPerIoOperationData->wsaBuf.buf = lpPerIoOperationData->buffer;
dwFlags = 0;
if(WSARecv(acceptSock, &(lpPerIoOperationData->wsaBuf), 1, &dwBytesRecv, &dwFlags, &(lpPerIoOperationData->wsaOverlapped), NULL) == SOCKET_ERROR)
{
if(WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() failed, error %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
}
else
{
printf("WSARecv() is OK!\n");
}
}
if(WSACleanup() == SOCKET_ERROR)
{
printf("WSACleanup() failed, error:%d.\n", WSAGetLastError());
}
else
{
printf("WSACleanup() is OK!.\n");
}
}
DWORD WINAPI ServerWorkerThread(LPVOID lpCompletionPortID)
{
HANDLE hCompletionPort = (HANDLE)lpCompletionPortID;
DWORD dwBytesTransferred = 0;
LPPER_HANDLE_DATA lpPerHandleData;
LPPER_IO_OPERATION_DATA lpPerIoData;
DWORD dwFlags;
while(TRUE)
{
if(GetQueuedCompletionStatus(hCompletionPort, &dwBytesTransferred,
(DWORD*)&lpPerHandleData, (LPOVERLAPPED*)&lpPerIoData, INFINITE) == 0)
{
printf("GetQueuedCompletionStatus() failed, error:%d.\n", GetLastError());
return 0;
}
else
{
printf("GetQueuedCompletionStatus() is OK!.\n");
}
if(dwBytesTransferred == 0)
{
printf("closing socket %d.\n", lpPerHandleData);
if(closesocket(lpPerHandleData->sock) == SOCKET_ERROR)
{
printf("closesocket() failed with error %d\n", WSAGetLastError());
return 0;
}
else
printf("closesocket() is fine!\n");
GlobalFree(lpPerHandleData);
GlobalFree(lpPerIoData);
continue;
}
else
{
printf("%s", lpPerIoData->buffer);
ZeroMemory(&(lpPerIoData->wsaOverlapped), sizeof(OVERLAPPED));
lpPerIoData->wsaBuf.len = DATA_BUFSIZE;
lpPerIoData->wsaBuf.buf = lpPerIoData->buffer;
dwFlags = 0;
if(WSARecv(lpPerHandleData->sock, &(lpPerIoData->wsaBuf), 1, &dwBytesTransferred, &dwFlags, &(lpPerIoData->wsaOverlapped), NULL) == SOCKET_ERROR)
{
if(WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() failed, error %d\n", WSAGetLastError());
return 1;
}
}
else
{
printf("WSARecv() is OK!\n");
}
}
}
}