// 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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.