#include <winsock2.h>
#include <stdio.h>
#include <windows.h>
#include <list>
#pragma comment(lib, "WS2_32.lib")
using namespace std;
LONG volatile g_ThreadNum; //线程数目
HANDLE g_hCompletion; //完成端口句柄
SOCKET g_socket; //sock
#define BUFFER_SIZE 20480 //最大缓冲
#define OP_READ 1 //网络读取
#define OP_WRITE 2 //网络写入
#define OP_ACCEPT 3 //网络连接
#pragma pack(1)
// per-handle数据
typedef struct _PER_HANDLE_DATA
{
SOCKET clientSocket; // 对应的套节字句柄
sockaddr_in addr; // 客户方地址
} PER_HANDLE_DATA, *PPER_HANDLE_DATA;
// per-I/O数据
typedef struct _PER_IO_DATA
{
OVERLAPPED ol; // 重叠结构
char buf[BUFFER_SIZE]; // 数据缓冲区
int nOperationType; // 操作类型
} PER_IO_DATA, *PPER_IO_DATA;
#pragma pack()
list<PPER_HANDLE_DATA> g_Arrar_per_handle_data;
DWORD WINAPI ServerThread(LPVOID lpParam)
{
//定义变量
HANDLE hCompletion = (HANDLE)lpParam;
DWORD dwTrans=0;
PPER_HANDLE_DATA pPerHandle=NULL;
PPER_IO_DATA pPerIO=NULL;
InterlockedIncrement(&g_ThreadNum);
while(TRUE)
{
// 在关联到此完成端口的所有套节字上等待I/O完成
BOOL bOK =GetQueuedCompletionStatus(hCompletion, &dwTrans, (LPDWORD)&pPerHandle, (LPOVERLAPPED*)&pPerIO, WSA_INFINITE);
//收到关闭通知
if (pPerHandle==NULL || pPerIO==NULL) break;
// 在此套节字上有错误发生
if(!bOK)
{
g_Arrar_per_handle_data.remove(pPerHandle);
closesocket(pPerHandle->clientSocket);
::GlobalFree(pPerHandle);
::GlobalFree(pPerIO);
continue;
}
// 套节字被对方关闭
if(dwTrans == 0 &&(pPerIO->nOperationType == OP_READ || pPerIO->nOperationType == OP_WRITE))
{
g_Arrar_per_handle_data.remove(pPerHandle);
closesocket(pPerHandle->clientSocket);
::GlobalFree(pPerHandle);
::GlobalFree(pPerIO);
continue;
}
switch(pPerIO->nOperationType) // 通过per-I/O数据中的nOperationType域查看什么I/O请求完成了
{
case OP_READ: // 完成一个接收请求
{
pPerIO->buf[dwTrans] = '\0';
printf(pPerIO -> buf);
//发送到单个客户端
//send(pPerHandle->clientSocket,pPerIO -> buf,dwTrans,NULL);
//所有客户端群发
list<PPER_HANDLE_DATA>::const_iterator cIterSocke;
for (cIterSocke = g_Arrar_per_handle_data.begin(); cIterSocke != g_Arrar_per_handle_data.end(); cIterSocke++)
{
send((*cIterSocke)->clientSocket,pPerIO -> buf,dwTrans,NULL);
}
// 继续投递接收I/O请求
WSABUF buf;
buf.buf = pPerIO->buf ;
buf.len = BUFFER_SIZE;
pPerIO->nOperationType = OP_READ;
DWORD nFlags = 0;
WSARecv(pPerHandle->clientSocket, &buf, 1, &dwTrans, &nFlags, &pPerIO->ol, NULL);
}
break;
case OP_WRITE: // 本例中没有投递这些类型的I/O请求
{
printf("OP_WRITE\n");
}
break;
case OP_ACCEPT:
{
printf("OP_ACCEPT\n");
}
break;
}
}
InterlockedDecrement(&g_ThreadNum);
return 0;
}
DWORD ThreadProc( LPVOID lpParameter)
{
g_Arrar_per_handle_data.clear();
int nPort = 4567;
// 创建完成端口对象,创建工作线程处理完成端口对象中事件
g_hCompletion = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
//队列工作项在线程池中的工作线程
QueueUserWorkItem(ServerThread, g_hCompletion, WT_EXECUTELONGFUNCTION);
//创建套接字
g_socket = socket(AF_INET, SOCK_STREAM, 0);
//绑定端口
SOCKADDR_IN si;
si.sin_family = AF_INET;
si.sin_port = ::ntohs(nPort);
si.sin_addr.S_un.S_addr = INADDR_ANY;
bind(g_socket, (sockaddr*)&si, sizeof(si));
//监听端口
listen(g_socket, SOMAXCONN);
// 循环处理到来的连接
while(TRUE)
{
// 等待接受未决的连接请求
SOCKADDR_IN saRemote;
int nRemoteLen = sizeof(saRemote);
SOCKET ClientNew = ::accept(g_socket, (sockaddr*)&saRemote, &nRemoteLen);
// 接受到新连接之后,为它创建一个per-handle数据,并将它们关联到完成端口对象。
PPER_HANDLE_DATA pPerHandle = (PPER_HANDLE_DATA)::GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));
pPerHandle->clientSocket = ClientNew;
memcpy(&pPerHandle->addr, &saRemote, nRemoteLen);
CreateIoCompletionPort((HANDLE)pPerHandle->clientSocket, g_hCompletion, (DWORD)pPerHandle, 0);
// 投递一个接收请求
PPER_IO_DATA pPerIO = (PPER_IO_DATA)::GlobalAlloc(GPTR, sizeof(PER_IO_DATA));
pPerIO->nOperationType = OP_READ;
WSABUF buf;
buf.buf = pPerIO->buf;
buf.len = BUFFER_SIZE;
DWORD dwRecv;
DWORD dwFlags = 0;
WSARecv(pPerHandle->clientSocket, &buf, 1, &dwRecv, &dwFlags, &pPerIO->ol, NULL);
g_Arrar_per_handle_data.push_back(pPerHandle);
//OutputDebugStringA(buf.buf);
}
return true;
}
void main()
{
// 初始化WS2_32.dll
WSADATA wsaData;
WORD sockVersion = MAKEWORD(2, 0);
WSAStartup(sockVersion, &wsaData);
CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)ThreadProc,NULL,NULL,NULL);
getchar();
//清理线程工作
while(g_ThreadNum > 0)
{
PostQueuedCompletionStatus(g_hCompletion, 0, 0, NULL);
Sleep(100);
}
list<PPER_HANDLE_DATA>::const_iterator cIterSocke;
for (cIterSocke = g_Arrar_per_handle_data.begin(); cIterSocke != g_Arrar_per_handle_data.end(); cIterSocke++)
{
closesocket((*cIterSocke)->clientSocket);
}
g_Arrar_per_handle_data.clear();
CloseHandle(g_hCompletion);
WSACleanup();
return;
}
IOCP例子一
最新推荐文章于 2022-01-10 22:34:35 发布