// iocpser.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#define PORT 9090
#define MSGSIZE 1024
#pragma comment(lib, "ws2_32.lib")
typedef enum
{
RECV_POSTED
}OPERATION_TYPE; //枚举,表示状态
typedef struct
{
WSAOVERLAPPED overlap;
WSABUF Buffer;
char szMessage[MSGSIZE];
struct sockaddr_in addr;
DWORD NumberOfBytesRecvd;
DWORD Flags;
OPERATION_TYPE OperationType;
}PER_IO_OPERATION_DATA, *LPPER_IO_OPERATION_DATA; //定义一个结构体保存IO数据
DWORD WINAPI WorkerThread(LPVOID);
int main()
{
WSADATA wsaData;
SOCKET sListen, sClient;
SOCKADDR_IN local, client;
DWORD i, dwThreadId;
int iaddrSize = sizeof(SOCKADDR_IN);
HANDLE CompletionPort = INVALID_HANDLE_VALUE;
HANDLE CompletionPort2 = INVALID_HANDLE_VALUE;
SYSTEM_INFO systeminfo;
LPPER_IO_OPERATION_DATA lpPerIOData = NULL;
INT32 fromaddr=sizeof(struct sockaddr_in);
UINT32 iocperrnum,recv=0;
//初始化Socket
WSAStartup(0x0202, &wsaData);
// 初始化完成端口
CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
// 有几个CPU就创建几个工作者线程
GetSystemInfo(&systeminfo);
for(i = 0; i < systeminfo.dwNumberOfProcessors+2; i++)
{
CreateThread(NULL, 0, WorkerThread, CompletionPort, 0, &dwThreadId);
}
// 创建套接字
sListen = socket(AF_INET, SOCK_DGRAM, 0);
// 绑定套接字
local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(PORT);
bind(sListen, (struct sockaddr *)&local, sizeof(SOCKADDR_IN));
// 开始监听!
//listen(sListen, 3);
//主进程的这个循环中循环等待客户端连接,若有连接,则将该客户套接字于完成端口绑定到一起
//然后开始异步等待接收客户传来的数据。
while (TRUE)
{
// 如果接到客户请求连接,则继续,否则等待。
// sClient = accept(sListen, (struct sockaddr *)&client, &iaddrSize);
//client中保存用户信息。
// printf("Accepted client:%s:%dn", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
//将这个最新到来的客户套接字和完成端口绑定到一起。
//第三个参数表示传递的参数,这里就传递的客户套接字地址。
//最后一个参数为0 表示有和CPU一样的进程数。即1个CPU一个线程
CompletionPort2= CreateIoCompletionPort((HANDLE)sListen, CompletionPort, ( ULONG_PTR)sListen, 4);
if(CompletionPort2!=CompletionPort)
return 0;
//第三个sClient是传递的参数,传给了后面的线程函数的GetQueuedCompletionStatus了
// 初始化结构体 使用堆内存分配
lpPerIOData = (LPPER_IO_OPERATION_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PER_IO_OPERATION_DATA));
lpPerIOData->Buffer.len = MSGSIZE; // len=1024
lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
lpPerIOData->NumberOfBytesRecvd=MSGSIZE;
lpPerIOData->OperationType = RECV_POSTED; //操作类型
lpPerIOData->Flags=0;
while(1)
{
recv=WSARecvFrom(sListen,
&lpPerIOData->Buffer,
1,
&lpPerIOData->NumberOfBytesRecvd,
&lpPerIOData->Flags,
(struct sockaddr*)&lpPerIOData->addr,
&fromaddr,
&lpPerIOData->overlap,
NULL
);
//Sleep(1);
iocperrnum= WSAGetLastError();
/*
WSARecv(sClient, //异步接收消息,立刻返回。
&lpPerIOData->Buffer, //获得接收的数据
1, //The number of WSABUF structures in the lpBuffers array.
&lpPerIOData->NumberOfBytesRecvd, //接收到的字节数,如果错误返回0
&lpPerIOData->Flags, //参数,先不管
&lpPerIOData->overlap, //输入这个结构体咯。
NULL);
*/
}
printf("WSARecv 1 \n");
}
//向每个工作者线程都发送—个特殊的完成数据包。该函数会指示每个线程都“立即结束并退出”.
PostQueuedCompletionStatus(CompletionPort, 0xFFFFFFFF, 0, NULL);
CloseHandle(CompletionPort);
closesocket(sListen);
WSACleanup();
return 0;
}
//工作者线程有一个参数,是指向完成端口的句柄
DWORD WINAPI WorkerThread(LPVOID CompletionPortID)
{
HANDLE CompletionPort=(HANDLE)CompletionPortID;
DWORD dwBytesTransferred;
SOCKET sClient;
LPPER_IO_OPERATION_DATA lpPerIOData = NULL;
INT32 fromaddr=sizeof(struct sockaddr);
UINT32 recv;
while (TRUE)
{
printf("enter WorkerThread \n");
//无限等待咯。不超时的那种。
if( GetQueuedCompletionStatus( //遇到可以接收数据则返回,否则等待
CompletionPort,
&dwBytesTransferred, //返回的字数
(PULONG_PTR)&sClient, //是响应的哪个客户套接字?
(LPOVERLAPPED *)&lpPerIOData, //得到该套接字保存的IO信息
INFINITE)==FALSE )
return 1;
if (dwBytesTransferred == 0xFFFFFFFF)
{
printf("dwBytesTransferred = 0xFFFFFFFF \n");
return 0;
}
if (dwBytesTransferred == 0)
{
printf("dwBytesTransferred = 0 \n");
//失去客户端连接
closesocket(sClient);
HeapFree(GetProcessHeap(), 0, lpPerIOData); //释放结构体
}
if(lpPerIOData->OperationType == RECV_POSTED) //如果收到数据
{
//lpPerIOData->szMessage[dwBytesTransferred] = ' ';//收到的数据最后一位是结束标志
printf("Message get:%d ,%s \n",lpPerIOData->addr.sin_addr.S_un.S_addr,lpPerIOData->Buffer.buf);
//sendto(sClient, lpPerIOData->Buffer.buf, lpPerIOData->Buffer.len, 0,(struct sockaddr*)&lpPerIOData->addr,sizeof(struct sockaddr)); //将接收到的消息返回
// Launch another asynchronous operation for sClient
/* memset(lpPerIOData, 0, sizeof(PER_IO_OPERATION_DATA));
lpPerIOData->Buffer.len = MSGSIZE; // len=1024
lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
lpPerIOData->NumberOfBytesRecvd=MSGSIZE;
lpPerIOData->OperationType = RECV_POSTED; //操作类型
lpPerIOData->Flags=0;
recv=WSARecvFrom(sClient,
&lpPerIOData->Buffer,
1,
&lpPerIOData->NumberOfBytesRecvd,
&lpPerIOData->Flags,
(struct sockaddr*)&lpPerIOData->addr,
&fromaddr,
&lpPerIOData->overlap,
NULL
);
printf("recv %d",recv);
*/
/*
WSARecv(sClient, //循环接收
&lpPerIOData->Buffer,
1,
&lpPerIOData->NumberOfBytesRecvd,
&lpPerIOData->Flags,
&lpPerIOData->overlap,
NULL);
*/
}
}
return 0;
}
/*
#pragma argsused
#pragma comment(lib,"ws2_32.lib")
#include <stdio.h>
#include <memory.h>
#include <winsock2.h>
#include <iostream>
using namespace std;
#define RECV_POSTED 1001
#define SEND_POSTED 1002
int Init();
HANDLE hCompletionPort;
typedef struct _PER_HANDLE_DATA
{
SOCKET sock;
}PER_HANDLE_DATA,* LPPER_HANDLE_DATA;
typedef struct _PER_IO_OPERATION_DATA
{
OVERLAPPED Overlapped;
WSABUF DataBuff[1];
char Buff[24];
BOOL OperationType;
}PER_IO_OPERATION_DATA,* LPPER_IO_OPERATION_DATA;
DWORD WINAPI ServerWorkerThread(LPVOID CompletionPort);
int main(int argc, char* argv[])
{
LPPER_HANDLE_DATA perHandleData;
LPPER_IO_OPERATION_DATA ioperdata;
SYSTEM_INFO siSys;
SOCKET sockListen;
struct sockaddr_in addrLocal;
char buf[24];
int nRet = 0;
DWORD nThreadID;
SOCKET sockAccept;
DWORD dwFlags;
DWORD dwRecvBytes;
int nReuseAddr = 1;
cout<<"初始环境..."<<endl;
if(Init() != 0)
goto theend;
//创建一个IO完成端口
cout<<"创建一个IO完成端口"<<endl;
hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
if(hCompletionPort == INVALID_HANDLE_VALUE)
{
cout<<"创建IO完成端口失败"<<endl;
goto theend;
}
//获取CPU数目
GetSystemInfo(&siSys);
//创建一定数目的工作者线程,本例中以一个处理器一个线程搭配
for(int i = 0;i<(int)siSys.dwNumberOfProcessors*2;i++)//NumberOfProcessors
{
HANDLE hThread;
hThread = CreateThread(NULL,0,ServerWorkerThread,(LPVOID)hCompletionPort,0,&nThreadID);
cout<<"创建工作者线程"<<i<<endl;
CloseHandle(hThread);
}
//创建监听SOCKET
cout<<"创建监听SOCKET"<<endl;
sockListen = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
if(sockListen == SOCKET_ERROR)
{
cout<<"WSASocket错误"<<endl;
goto theend;
}
if(setsockopt(sockListen,SOL_SOCKET,SO_REUSEADDR,(const char *)&nReuseAddr,sizeof(int)) != 0)
{
cout<<"setsockopt错误"<<endl;
goto theend;
}
addrLocal.sin_family = AF_INET;
addrLocal.sin_addr.s_addr = htonl(INADDR_ANY);
addrLocal.sin_port = htons(9090);
if(bind(sockListen,(struct sockaddr *)&addrLocal,sizeof(sockaddr_in)) != 0)
{
cout<<"bind错误"<<endl;
int n = WSAGetLastError();
goto theend;
}
//准备监听
cout<<"准备监听"<<endl;
if(listen(sockListen,5)!=0)
{
cout<<"listen错误"<<endl;
goto theend;
}
while(true)
{
//接收用户连接,被和完成端口关联
sockAccept = WSAAccept(sockListen,NULL,NULL,NULL,0);
perHandleData = (LPPER_HANDLE_DATA)malloc(sizeof(PER_HANDLE_DATA));
if(perHandleData == NULL)
continue;
cout<<"socket number "<<sockAccept<<"接入"<<endl;
perHandleData->sock = sockAccept;
ioperdata = (LPPER_IO_OPERATION_DATA)malloc(sizeof(PER_IO_OPERATION_DATA));
memset(&(ioperdata->Overlapped),0,sizeof(OVERLAPPED));
(ioperdata->DataBuff[0]).len = 24;
(ioperdata->DataBuff[0]).buf = ioperdata->Buff;
ioperdata->OperationType = RECV_POSTED;
if( ioperdata == NULL)
{
free(perHandleData);
continue;
}
//关联
cout<<"关联SOCKET和完成端口"<<endl;
if(CreateIoCompletionPort((HANDLE)sockAccept,hCompletionPort,(DWORD)perHandleData,1) == NULL)
{
cout<<sockAccept<<"createiocompletionport错误"<<endl;
free(perHandleData);
free(ioperdata);
continue;
}
//投递接收操作
cout<<"投递接收操作"<<endl;
WSARecv(perHandleData->sock,ioperdata->DataBuff,1,&dwRecvBytes,&dwFlags,&(ioperdata->Overlapped),NULL);
}
theend:
getchar();
return 0;
}
//---------------------------------------------------------------------------
int Init()
{
WSAData wsaData;
if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0)
{
cout<<"WSAStartup失败"<<endl;
return -1;
}
if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
cout<<"SOCKET版本不对"<<endl;
WSACleanup();
return -1;
}
return 0;
}
DWORD WINAPI ServerWorkerThread(LPVOID CompletionPort)
{
HANDLE ComPort = (HANDLE)CompletionPort;
DWORD BytesTransferred;
LPOVERLAPPED Overlapped;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
DWORD SendBytes,RecvBytes;
DWORD Flags;
BOOL bT;
while(TRUE)
{
//等待完成端口上SOCKET的完成
cout<<"等待完成端口上SOCKET的完成"<<endl;
bT = GetQueuedCompletionStatus(ComPort,
&BytesTransferred,(LPDWORD)&PerHandleData,
(LPOVERLAPPED *)&PerIoData,INFINITE);
//检查是否有错误产生
if(BytesTransferred == 0 &&
(PerIoData->OperationType == RECV_POSTED ||
PerIoData->OperationType == SEND_POSTED))
{
//关闭SOCKET
cout<<PerHandleData->sock<<"SOCKET关闭"<<endl;
closesocket(PerHandleData->sock);
free(PerHandleData);
free(PerIoData);
continue;
}
//为请求服务
if(PerIoData->OperationType == RECV_POSTED)
{
//处理
cout<<"接收处理"<<endl;
cout<<PerHandleData->sock<<"SOCKET :"<<PerIoData->Buff<<endl;
//回应客户端
ZeroMemory(PerIoData->Buff,24);
strcpy(PerIoData->Buff,"OK");
Flags = 0;
ZeroMemory((LPVOID)&(PerIoData->Overlapped),sizeof(OVERLAPPED));
PerIoData->DataBuff[0].len = 2;
PerIoData->DataBuff[0].buf = PerIoData->Buff;
PerIoData->OperationType = SEND_POSTED;
WSASend(PerHandleData->sock,PerIoData->DataBuff,
1,&SendBytes,0,&(PerIoData->Overlapped),NULL);
}
else //if(PerIoData->OperationType == SEND_POSTED)
{
//发送时的处理
cout<<"发送处理"<<endl;
Flags = 0;
ZeroMemory((LPVOID)&(PerIoData->Overlapped),sizeof(OVERLAPPED));
ZeroMemory(PerIoData->Buff,24);
PerIoData->DataBuff[0].len = 24;
PerIoData->DataBuff[0].buf = PerIoData->Buff;
PerIoData->OperationType = RECV_POSTED;
WSARecv(PerHandleData->sock,PerIoData->DataBuff,
1,&RecvBytes,&Flags,&(PerIoData->Overlapped),NULL);
}
}
}
*/
UDP IOCP ser
最新推荐文章于 2024-04-29 18:22:57 发布