#include
<
stdio.h
>
#include < winsock2.h >
#pragma comment(lib, "ws2_32.lib")
#define PORT 5150
#define DATA_BUFSIZE 8192
/*
*无论何时调用重叠操作函数时,总是会通过其lpOverlapped参数传递一个OVERLAPPEDPLUS结构
*(例如WSASend、 WSARecv等函数)。这就允许你为每一个重叠调用操作设置某些操作状态信息,
*当操作结束后,你可以通过GetQueuedCompletionStatus()函数获得你自定义结构的指针。
*/
typedef struct
{
OVERLAPPED Overlapped;
WSABUF dataBuf;
char buffer[DATA_BUFSIZE];
int OpCode; // 传递操作码
}PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;
#define OP_READ 0
#define OP_WRITE 1
#define OP_ACCEPT 2
// 单句柄数据
typedef struct
{
SOCKET Socket;
}PER_HANDLE_DATA, * LPPER_HANDLE_DATA;
DWORD WINAPI ServerWorkerThread( void * completionPortID);
int main( int argc, char * argv[])
{
SOCKADDR_IN serverAddr;
SOCKET listenSocket;
SOCKET acceptSocket;
HANDLE completionPort;
WSADATA wsaData;
if (WSAStartup( 0x0202 , & wsaData) != 0 )
{
printf( " WSAStartup failed with error " );
return - 1 ;
}
// 建立完成端口
if ((completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL, 0 , 0 )) == NULL)
{
printf( " CreateIoCompletionPort failed with error: %d " , GetLastError());
return - 1 ;
}
SYSTEM_INFO systemInfo;
GetSystemInfo( & systemInfo);
DWORD threadID;
// 创建工作者线程
for ( int i = 0 ; i < systemInfo.dwNumberOfProcessors * 2 ; i ++ )
{
HANDLE threadHandle;
if ((threadHandle = CreateThread(NULL, 0 ,ServerWorkerThread,completionPort, 0 , & threadID)) == NULL)
{
printf( " CreateThread() failed with error %d " , GetLastError());
return - 1 ;
}
CloseHandle(threadHandle);
}
if ((listenSocket = WSASocket(AF_INET, SOCK_STREAM, 0 , NULL, 0 ,
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf( " WSASocket() failed with error %d " , WSAGetLastError());
return - 1 ;
}
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(PORT);
if (bind(listenSocket,(sockaddr * ) & serverAddr, sizeof (serverAddr)) == SOCKET_ERROR)
{
printf( " bind() failed with error %d " , WSAGetLastError());
return - 1 ;
}
if (listen(listenSocket, 10 ) == SOCKET_ERROR)
{
printf( " listen() failed with error %d " , WSAGetLastError());
return - 1 ;
}
for (;;)
{
if ((acceptSocket = WSAAccept(listenSocket,NULL,NULL,NULL, 0 )) == SOCKET_ERROR)
{
printf( " WSAAccept() failed with error %d " , WSAGetLastError());
return - 1 ;
}
LPPER_HANDLE_DATA perHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR, sizeof (PER_HANDLE_DATA));
printf( " socket number %d connected " ,acceptSocket);
perHandleData -> Socket = acceptSocket;
// 新套接字句柄同完成端口关联到一起。
// 通过完成键(CompletionKey)参数,将单句柄数据结构传递给完成端口。
if (CreateIoCompletionPort((HANDLE)acceptSocket,completionPort,(DWORD)perHandleData,
0 ) == NULL)
{
printf( " CreateIoCompletionPort failed with error %d " , GetLastError());
return - 1 ;
}
// 为重叠调用建立单I/O操作数据
LPPER_IO_OPERATION_DATA perIoData;
perIoData = (LPPER_IO_OPERATION_DATA)GlobalAlloc(GPTR, sizeof (PER_IO_OPERATION_DATA));
memset( & perIoData -> Overlapped, 0 , sizeof (OVERLAPPED));
perIoData -> dataBuf.len = DATA_BUFSIZE;
perIoData -> dataBuf.buf = perIoData -> buffer;
perIoData -> OpCode = OP_READ; // 读操作
/* 开始在接受套接字上处理I/O
* 使用重叠I/O机制,在新建的套接字上投递一个或多个异步
* WSARecv 或 WSASend请求。这些I/O请求完成后,工作者线程
* 会为I/O请求提供服务。
*/
DWORD recvBytes;
DWORD flags = 0 ;
WSARecv(acceptSocket,
& (perIoData -> dataBuf),
1 ,
& recvBytes,
& flags,
& (perIoData -> Overlapped),
NULL);
}
return 0 ;
}
DWORD WINAPI ServerWorkerThread( void * completionPortID)
{
HANDLE completionPort = (HANDLE)completionPortID;
DWORD bytesTransferred;
// LPOVERLAPPED Overlapped;
LPPER_HANDLE_DATA perHandleData;
LPPER_IO_OPERATION_DATA perIoData;
while ( true )
{
if (GetQueuedCompletionStatus(completionPort, & bytesTransferred,
(LPDWORD) & perHandleData,(LPOVERLAPPED * ) & perIoData,INFINITE) == 0 )
{
printf( " GetQueuedCompletionStatus failed with error %d " , GetLastError());
return 0 ;
}
if (bytesTransferred == 0 )
{
printf( " Closing socket %d " ,perHandleData -> Socket);
closesocket(perHandleData -> Socket);
GlobalFree(perHandleData);
GlobalFree(perIoData);
continue ;
}
switch (perIoData -> OpCode)
{
case OP_ACCEPT:
break ;
case OP_WRITE: // 写完成
{
// 为下一个重叠调用建立单I/O操作数据
memset( & perIoData -> Overlapped, 0 , sizeof (OVERLAPPED));
perIoData -> dataBuf.len = DATA_BUFSIZE;
perIoData -> dataBuf.buf = perIoData -> buffer;
perIoData -> OpCode = OP_READ; // 读操作
DWORD recvBytes;
DWORD flags = 0 ;
WSARecv(perHandleData -> Socket,
& (perIoData -> dataBuf),
1 ,
& recvBytes,
& flags,
& (perIoData -> Overlapped),
NULL);
break ;
}
case OP_READ: // 读完成
{
printf( " recive socket %d :%s " ,perHandleData -> Socket,perIoData -> buffer);
// 为下一个重叠调用建立单I/O操作数据
// 将接收到的数据echo 回去
memset( & perIoData -> Overlapped, 0 , sizeof (OVERLAPPED));
perIoData -> dataBuf.buf = perIoData -> buffer;
perIoData -> dataBuf.len = bytesTransferred;
perIoData -> OpCode = OP_WRITE; // 写操作
DWORD bytesSend;
DWORD flags = 0 ;
WSASend(perHandleData -> Socket, & (perIoData -> dataBuf), 1 , & bytesSend,
0 , & (perIoData -> Overlapped), 0 );
break ;
}
}
}
}
#include < winsock2.h >
#pragma comment(lib, "ws2_32.lib")
#define PORT 5150
#define DATA_BUFSIZE 8192
/*
*无论何时调用重叠操作函数时,总是会通过其lpOverlapped参数传递一个OVERLAPPEDPLUS结构
*(例如WSASend、 WSARecv等函数)。这就允许你为每一个重叠调用操作设置某些操作状态信息,
*当操作结束后,你可以通过GetQueuedCompletionStatus()函数获得你自定义结构的指针。
*/
typedef struct
{
OVERLAPPED Overlapped;
WSABUF dataBuf;
char buffer[DATA_BUFSIZE];
int OpCode; // 传递操作码
}PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;
#define OP_READ 0
#define OP_WRITE 1
#define OP_ACCEPT 2
// 单句柄数据
typedef struct
{
SOCKET Socket;
}PER_HANDLE_DATA, * LPPER_HANDLE_DATA;
DWORD WINAPI ServerWorkerThread( void * completionPortID);
int main( int argc, char * argv[])
{
SOCKADDR_IN serverAddr;
SOCKET listenSocket;
SOCKET acceptSocket;
HANDLE completionPort;
WSADATA wsaData;
if (WSAStartup( 0x0202 , & wsaData) != 0 )
{
printf( " WSAStartup failed with error " );
return - 1 ;
}
// 建立完成端口
if ((completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL, 0 , 0 )) == NULL)
{
printf( " CreateIoCompletionPort failed with error: %d " , GetLastError());
return - 1 ;
}
SYSTEM_INFO systemInfo;
GetSystemInfo( & systemInfo);
DWORD threadID;
// 创建工作者线程
for ( int i = 0 ; i < systemInfo.dwNumberOfProcessors * 2 ; i ++ )
{
HANDLE threadHandle;
if ((threadHandle = CreateThread(NULL, 0 ,ServerWorkerThread,completionPort, 0 , & threadID)) == NULL)
{
printf( " CreateThread() failed with error %d " , GetLastError());
return - 1 ;
}
CloseHandle(threadHandle);
}
if ((listenSocket = WSASocket(AF_INET, SOCK_STREAM, 0 , NULL, 0 ,
WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf( " WSASocket() failed with error %d " , WSAGetLastError());
return - 1 ;
}
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(PORT);
if (bind(listenSocket,(sockaddr * ) & serverAddr, sizeof (serverAddr)) == SOCKET_ERROR)
{
printf( " bind() failed with error %d " , WSAGetLastError());
return - 1 ;
}
if (listen(listenSocket, 10 ) == SOCKET_ERROR)
{
printf( " listen() failed with error %d " , WSAGetLastError());
return - 1 ;
}
for (;;)
{
if ((acceptSocket = WSAAccept(listenSocket,NULL,NULL,NULL, 0 )) == SOCKET_ERROR)
{
printf( " WSAAccept() failed with error %d " , WSAGetLastError());
return - 1 ;
}
LPPER_HANDLE_DATA perHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR, sizeof (PER_HANDLE_DATA));
printf( " socket number %d connected " ,acceptSocket);
perHandleData -> Socket = acceptSocket;
// 新套接字句柄同完成端口关联到一起。
// 通过完成键(CompletionKey)参数,将单句柄数据结构传递给完成端口。
if (CreateIoCompletionPort((HANDLE)acceptSocket,completionPort,(DWORD)perHandleData,
0 ) == NULL)
{
printf( " CreateIoCompletionPort failed with error %d " , GetLastError());
return - 1 ;
}
// 为重叠调用建立单I/O操作数据
LPPER_IO_OPERATION_DATA perIoData;
perIoData = (LPPER_IO_OPERATION_DATA)GlobalAlloc(GPTR, sizeof (PER_IO_OPERATION_DATA));
memset( & perIoData -> Overlapped, 0 , sizeof (OVERLAPPED));
perIoData -> dataBuf.len = DATA_BUFSIZE;
perIoData -> dataBuf.buf = perIoData -> buffer;
perIoData -> OpCode = OP_READ; // 读操作
/* 开始在接受套接字上处理I/O
* 使用重叠I/O机制,在新建的套接字上投递一个或多个异步
* WSARecv 或 WSASend请求。这些I/O请求完成后,工作者线程
* 会为I/O请求提供服务。
*/
DWORD recvBytes;
DWORD flags = 0 ;
WSARecv(acceptSocket,
& (perIoData -> dataBuf),
1 ,
& recvBytes,
& flags,
& (perIoData -> Overlapped),
NULL);
}
return 0 ;
}
DWORD WINAPI ServerWorkerThread( void * completionPortID)
{
HANDLE completionPort = (HANDLE)completionPortID;
DWORD bytesTransferred;
// LPOVERLAPPED Overlapped;
LPPER_HANDLE_DATA perHandleData;
LPPER_IO_OPERATION_DATA perIoData;
while ( true )
{
if (GetQueuedCompletionStatus(completionPort, & bytesTransferred,
(LPDWORD) & perHandleData,(LPOVERLAPPED * ) & perIoData,INFINITE) == 0 )
{
printf( " GetQueuedCompletionStatus failed with error %d " , GetLastError());
return 0 ;
}
if (bytesTransferred == 0 )
{
printf( " Closing socket %d " ,perHandleData -> Socket);
closesocket(perHandleData -> Socket);
GlobalFree(perHandleData);
GlobalFree(perIoData);
continue ;
}
switch (perIoData -> OpCode)
{
case OP_ACCEPT:
break ;
case OP_WRITE: // 写完成
{
// 为下一个重叠调用建立单I/O操作数据
memset( & perIoData -> Overlapped, 0 , sizeof (OVERLAPPED));
perIoData -> dataBuf.len = DATA_BUFSIZE;
perIoData -> dataBuf.buf = perIoData -> buffer;
perIoData -> OpCode = OP_READ; // 读操作
DWORD recvBytes;
DWORD flags = 0 ;
WSARecv(perHandleData -> Socket,
& (perIoData -> dataBuf),
1 ,
& recvBytes,
& flags,
& (perIoData -> Overlapped),
NULL);
break ;
}
case OP_READ: // 读完成
{
printf( " recive socket %d :%s " ,perHandleData -> Socket,perIoData -> buffer);
// 为下一个重叠调用建立单I/O操作数据
// 将接收到的数据echo 回去
memset( & perIoData -> Overlapped, 0 , sizeof (OVERLAPPED));
perIoData -> dataBuf.buf = perIoData -> buffer;
perIoData -> dataBuf.len = bytesTransferred;
perIoData -> OpCode = OP_WRITE; // 写操作
DWORD bytesSend;
DWORD flags = 0 ;
WSASend(perHandleData -> Socket, & (perIoData -> dataBuf), 1 , & bytesSend,
0 , & (perIoData -> Overlapped), 0 );
break ;
}
}
}
}