windows 完成端口模型服务端
#include<iostream>
#include<winsock2.h>
#pragma comment(lib,"WS2_32.lib")
using namespace std;
const int ServerPort=4399;
const int MSGSIZE=1024;
typedef enum
{
RECV_POST,
SEND_POST
}OPERATION_TYPE;
typedef struct
{
WSAOVERLAPPED wsaOverlapped;
WSABUF wsaBuffer;
char dataBuffer[MSGSIZE];
DWORD recvedDataSize;
DWORD flags;
OPERATION_TYPE operationType;
}COM_IO_OPERATION_DATA,*PIO_OPERATION_DATA;
typedef struct _completionKey
{
SOCKET sock;
SOCKADDR_IN sockAddr;
}COMPLETION_KEY,*PCOMPLITON_KEY;
int LoadSocketLib()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return -1;
}
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 ) {
WSACleanup( );
return -1;
}
return 0;
}
DWORD WINAPI HandleThread(LPVOID completionPortID);
BOOL AsyncRecvData(SOCKET clientSOCK);
int main()
{
system("color 2f");
//加载套接字库
if(LoadSocketLib()!=0)
{
cout<<"Load winsock failed"<<endl;
return -1;
}
//创建完成端口
HANDLE completionPort=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
if(completionPort==NULL)
{
cout<<"创建完成端口失败"<<endl;
return -1;
}
SYSTEM_INFO systemInfo;
GetSystemInfo(&systemInfo);
DWORD dw_ThreadId;//线程ID
//创建线程池
for(int i=0;i<systemInfo.dwNumberOfProcessors;i++)
{
CreateThread(NULL,0,HandleThread,completionPort,0,&dw_ThreadId);
}
//创建套接字、绑定、设为监听状态
SOCKET serverSock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(serverSock==INVALID_SOCKET)
{
cout<<"create socket failed"<<endl;
return -1;
}
SOCKADDR_IN serverAddr;
serverAddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
serverAddr.sin_family=AF_INET;
serverAddr.sin_port=htons(ServerPort);
if(SOCKET_ERROR==bind(serverSock,(SOCKADDR*)&serverAddr,sizeof(SOCKADDR_IN)))
{
cout<<"binding failed"<<endl;
return -1;
}
if(SOCKET_ERROR==listen(serverSock,5))
{
cout<<"listen failed"<<endl;
return -1;
}
//接受客户端连接请求,并关联到完成端口
SOCKADDR_IN clientAddr;
int addrSize=sizeof(SOCKADDR_IN);
// PIO_OPERATION_DATA lpper_IO_Data=NULL;
cout<<"/t/t/t"<<"...Server begin..."<<endl;
PCOMPLITON_KEY pCompletion=NULL;
while(1)
{
SOCKET clientSock=accept(serverSock,(SOCKADDR*)&clientAddr,&addrSize);
if(clientSock==INVALID_SOCKET)
{
closesocket(clientSock);
continue;
}
//pCompletion=(PCOMPLITON_KEY)malloc(sizeof(COMPLETION_KEY));
// pCompletion->sock=clientSock;
//pCompletion->sockAddr=clientAddr;
cout<<"the client addr is..."<<inet_ntoa(clientAddr.sin_addr)<<"/t"<<ntohs(clientAddr.sin_port)<<endl;
if(NULL==CreateIoCompletionPort((HANDLE)clientSock,completionPort,/*(DWORD)pCompletion*/(DWORD)clientSock,0))
{
cout<<"套接字关联失败"<<endl;
closesocket(clientSock);
continue;
}
AsyncRecvData(clientSock);//发起异步接受操作
}
PostQueuedCompletionStatus(completionPort,0xFFFFFFFF,0,NULL);
CloseHandle(completionPort);
closesocket(serverSock);
WSACleanup();
return 0;
}
BOOL AsyncRecvData(SOCKET clientSock)
{
PIO_OPERATION_DATA lpper_IO_Data=NULL;
lpper_IO_Data=(PIO_OPERATION_DATA)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(PIO_OPERATION_DATA));//从堆中分配内存块给关联结构体
if(lpper_IO_Data==NULL)
{
cout<<"allocate failed"<<endl;
closesocket(clientSock);
//continue;
return false;
}
ZeroMemory(&lpper_IO_Data->wsaOverlapped,sizeof(lpper_IO_Data->wsaOverlapped));
lpper_IO_Data->wsaBuffer.len=MSGSIZE;
lpper_IO_Data->wsaBuffer.buf=lpper_IO_Data->dataBuffer;
lpper_IO_Data->operationType=RECV_POST;
//异步调用,因此当服务器刚开启的时候第一次激发异步接受Recv会失败,
if(SOCKET_ERROR==WSARecv(clientSock,&(lpper_IO_Data->wsaBuffer),1,&lpper_IO_Data->recvedDataSize,&lpper_IO_Data->flags,&lpper_IO_Data->wsaOverlapped,NULL))
{
if(WSAGetLastError()!=ERROR_IO_PENDING)
{
cout<<"WSARecv 函数调用失败"<<WSAGetLastError<<endl;//71A23CCE
closesocket(clientSock);
}
}
return true;
}
DWORD WINAPI HandleThread(LPVOID completionPortID)
{
HANDLE completionPort=(HANDLE)completionPortID;
DWORD dwBytesTransferred;
SOCKET clientSock;
PIO_OPERATION_DATA lp_IO_Data=NULL;
//从队列中取出活跃套接字
GetQueuedCompletionStatus(completionPort,&dwBytesTransferred,(unsigned long*)&clientSock,(LPWSAOVERLAPPED*)&lp_IO_Data,INFINITE);
if(dwBytesTransferred==0xFFFFFFFF)
{//没有活跃套接字
return 0;
}
if(lp_IO_Data->operationType==RECV_POST)
{
if(dwBytesTransferred==0)
{//客户端关闭
cout<<"客户端关闭"<<endl;
closesocket(clientSock);
HeapFree(GetProcessHeap(),0,lp_IO_Data);
}
else
{//处理客户端请求
lp_IO_Data->dataBuffer[dwBytesTransferred]='/0';
//send(clientSock,lp_IO_Data->dataBuffer,dwBytesTransferred,0);
WSASend(clientSock,&lp_IO_Data->wsaBuffer,1,&lp_IO_Data->recvedDataSize,lp_IO_Data->flags,&lp_IO_Data->wsaOverlapped,NULL);
memset(lp_IO_Data,0,sizeof(COM_IO_OPERATION_DATA));
lp_IO_Data->wsaBuffer.buf=lp_IO_Data->dataBuffer;
lp_IO_Data->wsaBuffer.len=MSGSIZE;
lp_IO_Data->operationType=RECV_POST;
WSARecv(clientSock,&lp_IO_Data->wsaBuffer,1,&lp_IO_Data->recvedDataSize,&lp_IO_Data->flags,&lp_IO_Data->wsaOverlapped,NULL);
}
}
return 0;
}