// Server.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")
#define DEFAULT_PORT 5018
#define DATA_BUFSIZE 8192
typedef struct _BUFFER_OBJ
{
OVERLAPPED Overlapped;
WSABUF DataBuf;
CHAR Buffer[DATA_BUFSIZE];
DWORD BytesSEND;
DWORD BytesRECV;
}BUFFER_OBJ,*LPBUFFER_OBJ;
typedef struct _SOCKET_OBJ
{
SOCKET Socket;
}SOCKET_OBJ, *LPSOCKET_OBJ;
DWORD WINAPI ServerWorkerThread(LPVOID lpParamer);
void main( void )
{
// 初始化
WSADATA data;
if(WSAStartup(MAKEWORD(2,2),&data) != 0)
{
printf("WSAStartup failed with error %d/n ", WSAGetLastError());
return;
}
// 创建完成端口
HANDLE hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL,0,0);
if(hIocp == NULL)
{
printf(" CreateIoCompletionPort failed with error: %d/n", GetLastError());
return;
}
// 获取CPU个数,创建2*CPU个数工作线程
DWORD ThreadID;
SYSTEM_INFO info;
GetSystemInfo(&info);
for(int i=0 ; i<info.dwNumberOfProcessors*2; i++)
{
HANDLE hThread = CreateThread(NULL,0,ServerWorkerThread, hIocp,0,&ThreadID);
if(hThread == NULL)
{
printf("CreateThread() failed with error %d/n",GetLastError());
return;
}
// 关闭线程句柄
CloseHandle(hThread);
}
// 创建监听套接字
SOCKET sListen = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
if(sListen == INVALID_SOCKET)
{
printf( " WSASocket() failed with error %d/n " , WSAGetLastError());
return;
}
// 绑定监听端口
SOCKADDR_IN local;
local.sin_family = AF_INET;
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_port = htons(DEFAULT_PORT);
if(bind(sListen,(PSOCKADDR)&local,sizeof (local)) == SOCKET_ERROR)
{
printf(" bind() failed with error %d/n",WSAGetLastError());
return;
}
// 开始监听客户端连接
if(listen(sListen,10) == SOCKET_ERROR)
{
printf("listen() failed with error %d/n",WSAGetLastError());
return;
}
LPSOCKET_OBJ pSockObj = NULL;
LPBUFFER_OBJ pBufferObj = NULL;
SOCKET sAccept;
DWORD RecvBytes;
DWORD Flags;
// 等待客户连接......
while (TRUE)
{
// 接受连接
if((sAccept = WSAAccept(sListen,NULL,NULL,NULL,0)) == SOCKET_ERROR)
{
printf("WSAAccept() failed with error %d/n",WSAGetLastError());
return;
}
// 分配空间
if((pSockObj = (LPSOCKET_OBJ)GlobalAlloc(GPTR,sizeof(SOCKET_OBJ))) == NULL)
{
printf("GlobalAlloc() failed with error %d/n",GetLastError());
return;
}
printf("Socket number %d connected/n",sAccept);
pSockObj->Socket = sAccept;
// 绑定被接受的套接字到完成端口上
if(CreateIoCompletionPort((HANDLE)sAccept,hIocp,(DWORD)pSockObj,0) == NULL)
{
printf( " CreateIoCompletionPort failed with error %d/n " , GetLastError());
return;
}
// 分配接收缓冲区
if ((pBufferObj = (LPBUFFER_OBJ)GlobalAlloc(GPTR,sizeof(BUFFER_OBJ))) == NULL)
{
printf("GlobalAlloc() failed with error %d/n",GetLastError());
return;
}
// 投递接收请求消息
ZeroMemory( & (pBufferObj->Overlapped), sizeof(OVERLAPPED));
pBufferObj->BytesSEND = 0 ;
pBufferObj->BytesRECV = 0 ;
pBufferObj->DataBuf.len = DATA_BUFSIZE;
pBufferObj->DataBuf.buf = pBufferObj->Buffer;
Flags = 0 ;
if(WSARecv(sAccept,&(pBufferObj->DataBuf),1,&RecvBytes,&Flags,
&(pBufferObj->Overlapped),NULL) == SOCKET_ERROR)
{
if(WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() failed with error %d/n ",WSAGetLastError());
return;
}
}
}
}
// 工作线程
DWORD WINAPI ServerWorkerThread(LPVOID lpParamer)
{
HANDLE hIOCP = (HANDLE)lpParamer;
DWORD BytesTransferred;
LPOVERLAPPED Overlapped;
LPSOCKET_OBJ pSockObj;
LPBUFFER_OBJ pBufferObj;
DWORD SendBytes;
DWORD RecvBytes;
DWORD Flags;
while (TRUE)
{
// 有消息来了
if(GetQueuedCompletionStatus(hIOCP,&BytesTransferred,
(LPDWORD)&pSockObj,(LPOVERLAPPED*)&pBufferObj,INFINITE) == 0)
{
printf("GetQueuedCompletionStatus failed with error %d/n",GetLastError());
return 0;
}
// 有人已经退出了
if(BytesTransferred == 0)
{
printf("Closing socket %d/n",pSockObj->Socket);
if(closesocket(pSockObj->Socket) == SOCKET_ERROR)
{
printf("closesocket() failed with error %d/n",WSAGetLastError());
return 0;
}
GlobalFree(pSockObj);
GlobalFree(pBufferObj);
continue;
}
if(pBufferObj->BytesRECV == 0)
{
pBufferObj->BytesRECV = BytesTransferred;
pBufferObj->BytesSEND = 0;
}
else
{
pBufferObj->BytesSEND += BytesTransferred;
}
// 投递发送请求消息
if(pBufferObj->BytesRECV > pBufferObj->BytesSEND)
{
ZeroMemory(&(pBufferObj->Overlapped),sizeof(OVERLAPPED));
pBufferObj->DataBuf.buf = pBufferObj->Buffer + pBufferObj->BytesSEND;
pBufferObj->DataBuf.len = pBufferObj->BytesRECV - pBufferObj->BytesSEND;
if (WSASend(pSockObj->Socket,&(pBufferObj->DataBuf),1 ,&SendBytes,0,
&(pBufferObj->Overlapped), NULL) == SOCKET_ERROR)
{
if(WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSASend() failed with error %d/n",WSAGetLastError());
return 0;
}
}
}
else // 再次投递接收请求消息
{
pBufferObj->BytesRECV = 0;
Flags = 0;
ZeroMemory(&(pBufferObj->Overlapped),sizeof(OVERLAPPED));
pBufferObj->DataBuf.len = DATA_BUFSIZE;
pBufferObj->DataBuf.buf = pBufferObj->Buffer;
if(WSARecv(pSockObj->Socket,&(pBufferObj->DataBuf),1,&RecvBytes,&Flags,
&(pBufferObj->Overlapped), NULL) == SOCKET_ERROR)
{
if(WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() failed with error %d/n",WSAGetLastError());
return 0;
}
}
}
}
}