// 重叠IO网络模式.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<WinSock2.h>
#include<windows.h>
#include<iostream>
using namespace std;
#pragma comment (lib,"ws2_32.lib")
#define PORT 6000
#define MSGSIZE 1024
typedef struct
{
WSAOVERLAPPED overlap;
WSABUF Buffer;
char szMessage[MSGSIZE];
DWORD NumberOfBytesRecvd;
DWORD Flags;
}PER_IO_OPERATION_DATA,*LPPER_IO_OPERATION_DATA;
int g_iToalComn = 0;
SOCKET g_CliSocketArr[MAXIMUM_WAIT_OBJECTS];
WSAEVENT g_CliEventArr[MAXIMUM_WAIT_OBJECTS];
LPPER_IO_OPERATION_DATA g_pPerIODataArr[MAXIMUM_WAIT_OBJECTS];
DWORD WINAPI WorkerThread(LPVOID lparam);
void Cleanup(int);
bool InitNetEvn()
{
WSADATA wsa;
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
cout << "网络环境失败" << endl;
return false;
}
if (LOBYTE(wsa.wVersion)!=2||HIBYTE(wsa.wVersion)!=2)
{
cout << "版本号不对" << endl;
return false;
}
return true;
}
int main()
{
SOCKET sListen, sClient;
SOCKADDR_IN local, client;
DWORD dwThreadId;
int iaddrSize = sizeof(SOCKADDR_IN);
if (!InitNetEvn())
{
return -1;
}
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(PORT);
bind(sListen, (sockaddr *)&local, iaddrSize);
listen(sListen, 3);
CreateThread(NULL, NULL, WorkerThread, NULL, NULL, &dwThreadId);
while (TRUE)
{
sClient = accept(sListen, (sockaddr *)&client, &iaddrSize);
printf("Accept client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
g_CliSocketArr[g_iToalComn] = sClient;
g_pPerIODataArr[g_iToalComn] = (LPPER_IO_OPERATION_DATA)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(PER_IO_OPERATION_DATA));
g_pPerIODataArr[g_iToalComn]->Buffer.len = MSGSIZE;
g_pPerIODataArr[g_iToalComn]->Buffer.buf = g_pPerIODataArr[g_iToalComn]->szMessage;
g_CliEventArr[g_iToalComn] = g_pPerIODataArr[g_iToalComn]->overlap.hEvent = WSACreateEvent();
WSARecv(
g_CliSocketArr[g_iToalComn],
&g_pPerIODataArr[g_iToalComn]->Buffer,
1,
&g_pPerIODataArr[g_iToalComn]->NumberOfBytesRecvd,
&g_pPerIODataArr[g_iToalComn]->Flags,
&g_pPerIODataArr[g_iToalComn]->overlap,
NULL);
g_iToalComn++;
}
closesocket(sListen);
WSACleanup();
return 0;
}
DWORD WINAPI WorkerThread(LPVOID lparam)
{
int ret, index;
DWORD cbTransferred;
while (true)
{
//判断出一个重叠IO调用是否完成
ret = WSAWaitForMultipleEvents(g_iToalComn, g_CliEventArr, FALSE, 1000, FALSE);
if (ret==WSA_WAIT_TIMEOUT||ret==WSA_WAIT_FAILED)
{
continue;
}
index = ret - WSA_WAIT_EVENT_0;
WSAResetEvent(g_CliEventArr[index]);
WSAGetOverlappedResult(
g_CliSocketArr[index],
&g_pPerIODataArr[index]->overlap,
&cbTransferred,
TRUE,
&g_pPerIODataArr[index]->Flags);
if (cbTransferred==0)
{
Cleanup(index);
}
else
{
g_pPerIODataArr[index]->szMessage[cbTransferred] = '\0';
send(g_CliSocketArr[index], g_pPerIODataArr[index]->szMessage, \
cbTransferred, 0);
WSARecv(
g_CliSocketArr[index],
&g_pPerIODataArr[index]->Buffer,
1,
&g_pPerIODataArr[index]->NumberOfBytesRecvd,
&g_pPerIODataArr[index]->Flags,
&g_pPerIODataArr[index]->overlap,
NULL);
}
}
return 0;
}
void Cleanup(int index)
{
closesocket(g_CliSocketArr[index]);
WSACloseEvent(g_CliEventArr[index]);
HeapFree(GetProcessHeap(), 0, g_pPerIODataArr[index]);
if (index<g_iToalComn-1)
{
g_CliSocketArr[index] = g_CliSocketArr[g_iToalComn - 1];
g_CliEventArr[index] = g_CliEventArr[g_iToalComn - 1];
g_pPerIODataArr[index] = g_pPerIODataArr[g_iToalComn - 1];
}
g_pPerIODataArr[--g_iToalComn] = NULL;
}