/*
WinSock I/O Module
---Completion Port Module
Server Example 1.0
*/
#include <winsock2.h>
#include <mswsock.h>
#include <iostream.h>
#include <conio.h>
#pragma comment(lib, "ws2_32.lib")
HANDLE hIocp;
SOCKET Listen;
//
//自定义结构,即“完成键”(单句柄数据)
//
typedef struct _PER_HANDLE_CONTEXT
{
SOCKET client;
_PER_HANDLE_CONTEXT* pNext;
}PER_HANDLE_CONTEXT, *PPER_HANDLE_CONTEXT;
#define BUFFER_SIZE 4096
typedef enum _IO_OPERATION
{
RECV = 1,
SEND
}IO_OPERATION, *PIO_OPERATION;
typedef struct _PER_IO_CONTEXT
{
WSAOVERLAPPED ol;
WSABUF wsaBuffer;
CHAR szBuffer[BUFFER_SIZE];
IO_OPERATION OpType;
_PER_IO_CONTEXT* pNext;
}PER_IO_CONTEXT, *PPER_IO_CONTEXT;
DWORD WINAPI CompletionRoutine(LPVOID lpParam);
DWORD WINAPI ThreadAccept(LPVOID lpParam);
char sendBuffer[] = "/t Welcome to Completion Port IO Module server/r/n";
void main()
{
WSADATA wsaData;
int nRet;
HANDLE hThread;
nRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(nRet != 0)
{
cout <<"WSAStartup Failed: " <<WSAGetLastError() <<endl;
return;
}
hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if (NULL == hIocp)
{
cout <<"CreateIoCompletionPort Failed: " <<GetLastError() <<endl;
WSACleanup();
return;
}
SYSTEM_INFO SysInfo;
GetSystemInfo(&SysInfo);
for (int i=0; i<(int)SysInfo.dwNumberOfProcessors; i++)
{
hThread = CreateThread(NULL, 0, CompletionRoutine, NULL, 0, NULL);
if(NULL == hThread)
{
cout <<"CreateThread Failed: " <<GetLastError() <<endl;
WSACleanup();
CloseHandle(hIocp);
return;
}
CloseHandle(hThread);
}
Listen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (INVALID_SOCKET == Listen)
{
cout <<"WSASocket Failed: " <<WSAGetLastError() <<endl;
WSACleanup();
PostQueuedCompletionStatus(hIocp, 0, NULL, NULL);
CloseHandle(hIocp);
return;
}
SOCKADDR_IN inAddr;
inAddr.sin_family = AF_INET;
inAddr.sin_addr.s_addr = htonl(INADDR_ANY);
inAddr.sin_port = htons(5150);
nRet = bind(Listen, (PSOCKADDR)&inAddr, sizeof(inAddr));
if (SOCKET_ERROR == nRet)
{
closesocket(Listen);
cout <<"bind Failed: " <<WSAGetLastError() <<endl;
WSACleanup();
PostQueuedCompletionStatus(hIocp, 0, NULL, NULL);
CloseHandle(hIocp);
return;
}
nRet = listen(Listen, 20);
if (SOCKET_ERROR == nRet)
{
closesocket(Listen);
cout <<"listen Failed: " <<WSAGetLastError() <<endl;
WSACleanup();
PostQueuedCompletionStatus(hIocp, 0, NULL, NULL);
CloseHandle(hIocp);
return;
}
hThread = CreateThread(NULL, 0, ThreadAccept, NULL, 0, NULL);
if(NULL == hThread)
{
closesocket(Listen);
cout <<"CreateThread Failed: " <<GetLastError() <<endl;
WSACleanup();
PostQueuedCompletionStatus(hIocp, 0, NULL, NULL);
CloseHandle(hIocp);
return;
}
CloseHandle(hThread);
cout <<"Enter 'q' to exit: " <<endl;
while(getch() != 'q');
closesocket(Listen);
WSACleanup();
PostQueuedCompletionStatus(hIocp, 0, NULL, NULL);
CloseHandle(hIocp);
cout <<"Main thread will exit " <<endl;
getch();
}
DWORD WINAPI ThreadAccept(LPVOID lpParam)
{
SOCKET client;
PPER_HANDLE_CONTEXT pHContext;
HANDLE hRet;
PPER_IO_CONTEXT pIContext;
int nRet;
while(true)
{
client = WSAAccept(Listen, NULL, NULL, NULL, 0);
if(client == INVALID_SOCKET)
{
cout <<"WSAAccept Failed: " <<WSAGetLastError() <<endl;
cout <<"ThreadAccept thread exit " <<endl;
return 0;
}
pHContext = (PPER_HANDLE_CONTEXT)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,sizeof(PER_HANDLE_CONTEXT));
if(NULL == pHContext)
{
cout <<"HeapAlloc Failed: " <<GetLastError() <<endl;
closesocket(client);
continue;
}
pHContext->client = client;
pHContext->pNext = NULL;
hRet = CreateIoCompletionPort((HANDLE)client, hIocp, (ULONG_PTR)pHContext, 0);
if(NULL == hRet)
{
cout <<"CreateIoCompletionPort Failed: " <<GetLastError() <<endl;
closesocket(client);
HeapFree(GetProcessHeap(), 0, pHContext);
continue;
}
pIContext = (PPER_IO_CONTEXT)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PER_IO_CONTEXT));
if(NULL == pIContext)
{
cout <<"HeapAlloc Failed: " <<GetLastError() <<endl;
closesocket(client);
HeapFree(GetProcessHeap(), 0, pHContext);
continue;
}
ZeroMemory(&(pIContext->ol), sizeof(pIContext->ol));
ZeroMemory(pIContext->szBuffer, BUFFER_SIZE);
pIContext->wsaBuffer.buf = pIContext->szBuffer;
pIContext->wsaBuffer.len = BUFFER_SIZE;
pIContext->OpType = RECV;
pIContext->pNext = NULL;
DWORD nRecv = 0;
DWORD nFlag = 0;
nRet = WSARecv(pHContext->client, &(pIContext->wsaBuffer), 1, &nRecv, &nFlag, &(pIContext->ol), NULL);
if(SOCKET_ERROR == nRet)
{
if(ERROR_IO_PENDING != WSAGetLastError())
{
cout <<"WSARecv Failed: " <<WSAGetLastError() <<endl;
closesocket(pHContext->client);
HeapFree(GetProcessHeap(), 0, pHContext);
HeapFree(GetProcessHeap(), 0, pIContext);
continue;
}
}
ZeroMemory(&(pIContext->ol), sizeof(pIContext->ol));
pIContext->wsaBuffer.buf = sendBuffer;
pIContext->wsaBuffer.len = strlen(sendBuffer);
pIContext->OpType = SEND;
pIContext->pNext = NULL;
DWORD nSend = 0;
nFlag = 0;
nRet = WSASend(pHContext->client, &(pIContext->wsaBuffer), 1, &nSend, nFlag, &(pIContext->ol), NULL);
if(SOCKET_ERROR == nRet)
{
if(ERROR_IO_PENDING != WSAGetLastError())
{
cout <<"WSASend Failed: " <<WSAGetLastError() <<endl;
closesocket(pHContext->client);
HeapFree(GetProcessHeap(), 0, pHContext);
HeapFree(GetProcessHeap(), 0, pIContext);
continue;
}
}
cout <<"Client connected with socket: " <<pHContext->client <<endl;
}
}
DWORD WINAPI CompletionRoutine(LPVOID lpParam)
{
DWORD dwBytes;
PPER_HANDLE_CONTEXT pHContext = NULL;
PPER_IO_CONTEXT pIContext = NULL;
LPWSAOVERLAPPED pOL = NULL;
int nRet;
BOOL bRet;
while(true)
{
bRet = GetQueuedCompletionStatus(hIocp, &dwBytes,(PULONG_PTR )&pHContext, &pOL, INFINITE);
if(FALSE == bRet)
{
cout <<"GetQueuedCompletionStatus Failed: " <<GetLastError() <<endl;
if((NULL != pOL) && (0 == dwBytes))
{
closesocket(pHContext->client);
cout <<"Client disconnected socket: " <<pHContext->client <<endl;
HeapFree(GetProcessHeap(), 0, pHContext);
HeapFree(GetProcessHeap(), 0, CONTAINING_RECORD(pOL, PER_IO_CONTEXT, ol));
}
continue;
}
if(NULL == pHContext)
{
cout <<"CompletionRoutine thread exit " <<endl;
return 0;
}
pIContext = CONTAINING_RECORD(pOL, PER_IO_CONTEXT, ol);
if(0 == dwBytes)
{
closesocket(pHContext->client);
cout <<"Client disconnected socket: " <<pHContext->client <<endl;
HeapFree(GetProcessHeap(), 0, pHContext);
HeapFree(GetProcessHeap(), 0, pIContext);
continue;
}
switch(pIContext->OpType)
{
case RECV:
cout << "Recv: " << pIContext->szBuffer << endl;
break;
case SEND:
cout << "Send: " << pIContext->wsaBuffer.buf << endl;
break;
default:
break;
}
ZeroMemory(&(pIContext->ol), sizeof(pIContext->ol));
ZeroMemory(pIContext->szBuffer, BUFFER_SIZE);
pIContext->wsaBuffer.buf = pIContext->szBuffer;
pIContext->wsaBuffer.len = BUFFER_SIZE;
pIContext->OpType = RECV;
pIContext->pNext = NULL;
DWORD nRecv = 0;
DWORD nFlag = 0;
nRet = WSARecv(pHContext->client, &(pIContext->wsaBuffer), 1, &nRecv, &nFlag, &(pIContext->ol), NULL);
if(SOCKET_ERROR == nRet)
{
if(ERROR_IO_PENDING != WSAGetLastError())
{
cout <<"WSARecv Failed: " <<WSAGetLastError() <<endl;
closesocket(pHContext->client);
HeapFree(GetProcessHeap(), 0, pHContext);
HeapFree(GetProcessHeap(), 0, pIContext);
continue;
}
}
}
}