#include <conio.h>
#include <stdio.h>
#include <winsock2.h>
#include "Globle.h"
#pragma comment(lib, "ws2_32.lib")
SOCKET Listen;
HANDLE ThreadPool[WSA_MAXIMUM_WAIT_EVENTS] = {NULL};
HANDLE hCompletionPort = NULL;
volatile int TotalClient = 0;
volatile BOOL bExit = FALSE;
static int nThreadCout = 0;
enum PostType{OP_RECV, OP_SEND, OP_EXIT};
typedef struct
{
OVERLAPPED Overlapped;
WSABUF DataBuf[2];
CHAR Buffer[2][BUFFER_SIZE];
DWORD dwOpType;
} PER_IO_OP_DATA, * LPPER_IO_OP_DATA;
void Init()
{
InitializeCriticalSection(&csGeneralData);
InitializeCriticalSection(&csShowMsg);
srand(time(0));
}
void BeforeExit()
{
DeleteCriticalSection(&csGeneralData);
DeleteCriticalSection(&csShowMsg);
}
DWORD WINAPI ConnThread(LPVOID lpParam)
{
char Msg[1024] = "";
ShowMsg("ConnThread start...");
DWORD dwCode;
DWORD dwRecv = 0;
DWORD dwFlag = 0;
while(!bExit)
{
SOCKET Client = accept(Listen, NULL, NULL);
if(Client == SOCKET_ERROR)
{
sprintf(Msg, "Accept error %d", ::WSAGetLastError());
ShowMsg(Msg);
continue;
}
sprintf(Msg, "Socket %d connected...", Client);
ShowMsg(Msg);
HANDLE hResult = CreateIoCompletionPort((HANDLE) Client, hCompletionPort, (DWORD)Client, 0);
if(NULL == hResult)
{
sprintf(Msg, "CreateIoCompletionPort() failed with error %d\n", GetLastError());
ShowMsg(Msg);
closesocket(Client);
continue;
}
LPPER_IO_OP_DATA lpPerIoData = (LPPER_IO_OP_DATA) GlobalAlloc(GPTR, sizeof(PER_IO_OP_DATA));
if (NULL == lpPerIoData)
{
sprintf(Msg, "GlobalAlloc() failed with error %d\n", GetLastError());
ShowMsg(Msg);
closesocket(Client);
continue;
}
lpPerIoData->dwOpType = OP_SEND;
lpPerIoData->DataBuf[0].len = BUFFER_SIZE;
lpPerIoData->DataBuf[0].buf = lpPerIoData->Buffer[0];
dwFlag = 0;
::InterlockedIncrement((LPLONG)&TotalClient);
dwCode = WSARecv(Client, lpPerIoData->DataBuf, 1, &dwRecv, &dwFlag,
&(lpPerIoData->Overlapped), NULL);
if (dwCode == SOCKET_ERROR)
{
dwCode = WSAGetLastError();
if (dwCode == ERROR_IO_PENDING) continue;
sprintf(Msg, "WSARecv() failed with error %d\n", dwCode);
ShowMsg(Msg);
closesocket(Client);
::GlobalFree(lpPerIoData);
::InterlockedDecrement((LPLONG)&TotalClient);
continue;
}
}
ShowMsg("ConnThread exit...");
return 0;
}
DWORD WINAPI WorkerThread(LPVOID lpParam)
{
char Buf[BUFFER_SIZE] = {0};
char Msg[1024] = "";
ShowMsg("WorkerThread start...");
HANDLE hPort = (HANDLE) lpParam;
DWORD dwTransferred;
SOCKET Client = INVALID_SOCKET;
LPPER_IO_OP_DATA lpPerIoData;
DWORD dwSendBytes, dwRecvBytes;
DWORD dwFlag;
DWORD dwCode;
while(!bExit)
{
lpPerIoData = NULL;
BOOL bResult = GetQueuedCompletionStatus(hPort, &dwTransferred,
(LPDWORD)&Client,
(LPOVERLAPPED *)&lpPerIoData,
200);
if (bResult == FALSE)
{
dwCode = GetLastError();
if(dwCode == WAIT_TIMEOUT) continue;
sprintf(Msg, "GetQueuedCompletionStatus failed with Code: %d\n", dwCode);
ShowMsg(Msg);
closesocket(Client);
GlobalFree(lpPerIoData);
::InterlockedDecrement((LPLONG)&TotalClient);
if(dwCode == (WSAEHOSTDOWN-WSABASEERR))
{
sprintf(Msg, "The destination host is down\n");
ShowMsg(Msg);
}
continue;
}
sprintf(Msg, "Total clients:%d", TotalClient);
ShowMsg(Msg);
if (dwTransferred == 0 && lpPerIoData->dwOpType != OP_EXIT)
{
sprintf(Msg, "Closing socket %d\n", Client);
ShowMsg(Msg);
GlobalFree(lpPerIoData);
dwCode = closesocket(Client);
if(dwCode == SOCKET_ERROR)
{
sprintf(Msg, "closesocket() failed with error %d\n", WSAGetLastError());
ShowMsg(Msg);
}
else
::InterlockedDecrement((LPLONG)&TotalClient);
continue;
}
if(lpPerIoData->dwOpType == OP_EXIT)
{
closesocket(Client);
GlobalFree(lpPerIoData);
::InterlockedDecrement((LPLONG)&TotalClient);
return 0;
}
dwFlag = 0;
switch(lpPerIoData->dwOpType)
{
case OP_SEND:
sprintf(Msg, "Socket %d Received:%s", Client, lpPerIoData->Buffer[0]);
ShowMsg(Msg);
ZeroMemory(&(lpPerIoData->Overlapped), sizeof(OVERLAPPED));
::GetData(lpPerIoData->Buffer[0]);
lpPerIoData->dwOpType = OP_RECV;
dwCode = WSASend(Client, lpPerIoData->DataBuf, 1, &dwSendBytes, dwFlag,
&(lpPerIoData->Overlapped), NULL);
if(dwCode == SOCKET_ERROR)
{
dwCode = WSAGetLastError();
if (dwCode == ERROR_IO_PENDING) continue;
closesocket(Client);
GlobalFree(lpPerIoData);
sprintf(Msg, "WSASend() failed with error %d\n", dwCode);
ShowMsg(Msg);
::InterlockedDecrement((LPLONG)&TotalClient);
}
break;
case OP_RECV:
sprintf(Msg, "Sended data to Socket %d:%s", Client, lpPerIoData->Buffer[0]);
ShowMsg(Msg);
ZeroMemory(&(lpPerIoData->Overlapped), sizeof(OVERLAPPED));
lpPerIoData->dwOpType = OP_SEND;
dwCode = WSARecv(Client, lpPerIoData->DataBuf, 1, &dwRecvBytes, &dwFlag,
&(lpPerIoData->Overlapped), NULL);
if(dwCode == SOCKET_ERROR)
{
dwCode = WSAGetLastError();
if (dwCode == ERROR_IO_PENDING) continue;
sprintf(Msg, "WSARecv() failed with error %d\n", dwCode);
ShowMsg(Msg);
closesocket(Client);
GlobalFree(lpPerIoData);
::InterlockedDecrement((LPLONG)&TotalClient);
}
break;
default:
continue;
}
}
ShowMsg("WorkerThread exit...");
return 0;
}
int main()
{
int i = 0;
DWORD dwCode;
WSADATA wsaData;
HANDLE hThread = NULL;
SYSTEM_INFO SystemInfo;
Init();
dwCode = WSAStartup(MAKEWORD(2,2), &wsaData);
if(dwCode != 0)
{
cout << "\nCan't find find a usable WinSock DLL" << endl;
goto EXIT;
}
if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 )
{
cout << "\nCan't find the socket version required." << endl;
goto EXIT;
}
Listen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(Listen == INVALID_SOCKET)
{
cout << "\nCan't create the socket:" << WSAGetLastError() << endl;
goto EXIT;
}
SOCKADDR_IN sockAddr;
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr = ADDR_ANY;
sockAddr.sin_port = htons(PORT);
dwCode = bind(Listen, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR));
if(dwCode == SOCKET_ERROR)
{
::closesocket(Listen);
cout << "\nCan't bind the socket:" << WSAGetLastError() << endl;
goto EXIT;
}
dwCode = listen(Listen, 20);
if(dwCode == SOCKET_ERROR)
{
::closesocket(Listen);
cout << "\nCan't listen:" << WSAGetLastError() << endl;
goto EXIT;
}
hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if (NULL == hCompletionPort)
{
::closesocket(Listen);
cout << "CreateIoCompletionPort failed with error" << GetLastError() << endl;
goto EXIT;
}
hThread = CreateThread(NULL, 0, ConnThread, 0, 0, NULL);
ThreadPool[nThreadCout++] = hThread;
GetSystemInfo(&SystemInfo);
for(i = 0; (DWORD)i < SystemInfo.dwNumberOfProcessors*2; i++)
{
hThread = CreateThread(NULL, 0, WorkerThread, hCompletionPort, 0, NULL);
ThreadPool[nThreadCout++] = hThread;
}
ShowMsg("Press 'q' to exit...\n");
while(_getch() != 'q' && _getch() != 'Q')
{
ShowMsg("Press 'q' to exit...\n");
}
bExit = TRUE;
::closesocket(Listen);
::WaitForMultipleObjects(nThreadCout, ThreadPool, TRUE, INFINITE);
::CloseHandle(hCompletionPort);
for(i = 0; i < nThreadCout; i++)
::CloseHandle(ThreadPool[i]);
EXIT:
WSACleanup();
BeforeExit();
printf("\nPress any key to exit...");
_getch();
return 0;
}