转载请注明来源:http://blog.csdn.net/caoshiying?viewmode=contents
HANDLE WINAPI CreateIoCompletionPort(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE ExistingCompletionPort,
_In_ ULONG_PTR CompletionKey,
_In_ DWORD NumberOfConcurrentThreads
);
BOOL WINAPI GetQueuedCompletionStatus(
_In_ HANDLE CompletionPort,
_Out_ LPDWORD lpNumberOfBytes,
_Out_ PULONG_PTR lpCompletionKey,
_Out_ LPOVERLAPPED *lpOverlapped,
_In_ DWORD dwMilliseconds
);
Windows Server 2003和Windows XP:关闭完成端口句柄,调用优秀不会导致之前的行为。该函数将继续等待直到一项是从港口或直到发生超时删除,如果指定以外的无限价值。
如果GetQueuedCompletionStatus函数调用成功,它出列完成包一个成功的I/O操作完成端口和存储信息的变量所指向的下列参数:lpNumberOfBytes,lpcompletionkey,和lpOverlapped。在失败(返回值是错误的),这些相同的参数可以包含特定的值组合如下:BOOL WINAPI PostQueuedCompletionStatus(
_In_ HANDLE CompletionPort,
_In_ DWORD dwNumberOfBytesTransferred,
_In_ ULONG_PTR dwCompletionKey,
_In_opt_ LPOVERLAPPED lpOverlapped
);
#pragma once
#define SOCKET_MESSAGE_SIZE 1024
#include
#include
typedef enum
{
RECV_POSTED
}OPERATION_TYPE;
typedef struct
{
WSAOVERLAPPED overlap;
WSABUF buffer;
char message[SOCKET_MESSAGE_SIZE];
DWORD received_count;
DWORD flags;
OPERATION_TYPE operation_type;
}PEERIO_OPERATION_DATA, *LPPEERIO_OPERATION_DATA;
class completeio_server_manager:
public iserver_manager
{
private:
int iport;
int iaddr_size;
common_callback callback;
BOOL brunning;
SOCKET server;
WSADATA wsaData;
HANDLE hcomplete_port;
SYSTEM_INFO system_info;
LPPEERIO_OPERATION_DATA peer_data;
bool bdisposed;
protected:
bool accept_by_crt();
bool accept_by_winapi();
public:
void receive();
void shutdown();
void start_receive();
void start_accept();
public:
completeio_server_manager();
virtual ~completeio_server_manager();
};
实现文件完整代码如下:
#include "completeio_server_manager.h"
#include
#include
completeio_server_manager::completeio_server_manager()
{
iport = 5150;
iaddr_size = sizeof(SOCKADDR_IN);
brunning = FALSE;
GetSystemInfo(&system_info);
callback.set_manager(this);
callback.set_receive_thread_coount(system_info.dwNumberOfProcessors);
hcomplete_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
bdisposed = false;
}
completeio_server_manager::~completeio_server_manager()
{
if (bdisposed)
shutdown();
}
bool completeio_server_manager::accept_by_crt()
{
return true;
}
bool completeio_server_manager::accept_by_winapi()
{
SOCKADDR_IN server_addr;
SOCKADDR_IN client_addr;
SOCKET client;
LPPEERIO_OPERATION_DATA peer_data;
int iresult = -1;
WSAStartup(MAKEWORD(2, 2), &wsaData);
server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(iport);
do
{
iresult = bind(server, (struct sockaddr*)&server_addr, iaddr_size);
if (iresult == SOCKET_ERROR)
{
iport++;
server_addr.sin_port = htons(iport);
}
} while (iresult == -1);
listen(server, 3);
printf("基于完成端口模型的Socket服务器启动成功。监听端口是:%d\n", iport);
while (brunning)
{
printf("开始监听请求。\n");
client = accept(server, (struct sockaddr*)&client_addr, &iaddr_size);
if (client == SOCKET_ERROR)
continue;
printf("新客户端连接:%s:%d\n", inet_ntoa(client_addr.sin_addr), htons(client_addr.sin_port));
CreateIoCompletionPort((HANDLE)client, hcomplete_port, (DWORD)client, 0);
peer_data = (LPPEERIO_OPERATION_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PEERIO_OPERATION_DATA));
peer_data->buffer.len = SOCKET_MESSAGE_SIZE;
peer_data->buffer.buf = peer_data->message;
peer_data->operation_type = RECV_POSTED;
printf("开始接收客户端传送数据。\n");
WSARecv(client, &peer_data->buffer, 1, &peer_data->received_count, &peer_data->flags, &peer_data->overlap, NULL);
printf("收到客户端数据。\n");
}
return true;
}
void completeio_server_manager::receive()
{
DWORD dwtransfered = 0;
SOCKET client;
LPPEERIO_OPERATION_DATA peer = nullptr;
while (brunning)
{
printf("线程:%d,查询端口状态信息。\n",GetCurrentThreadId());
GetQueuedCompletionStatus(hcomplete_port, &dwtransfered, (PULONG_PTR)&client, (LPOVERLAPPED*)&peer, INFINITE);
printf("获得端口信息。\n");
if (dwtransfered == 0xFFFFFFFF)
return;
if (peer->operation_type == RECV_POSTED)
{
if (dwtransfered == 0)
{
closesocket(client);
printf("有客户端退出了。\n");
HeapFree(GetProcessHeap(), 0, peer);
}
else
{
peer->message[dwtransfered] = 0;
send(client, peer->message, dwtransfered, 0);
memset(peer, 0, sizeof(PEERIO_OPERATION_DATA));
peer->buffer.len = SOCKET_MESSAGE_SIZE;
peer->buffer.buf = peer->message;
peer->operation_type = RECV_POSTED;
WSARecv(client, &peer->buffer, 1, &peer->received_count, &peer->flags, &peer->overlap, nullptr);
}
}
}
}
void completeio_server_manager::shutdown()
{
PostQueuedCompletionStatus(hcomplete_port, 0xFFFFFFFF, 0, NULL);//端口尾随数据。
brunning = FALSE;
callback.shutdown();//清扫
CloseHandle(hcomplete_port);
closesocket(server);
WSACleanup();
bdisposed = true;
}
void completeio_server_manager::start_accept()
{
brunning = TRUE;
bdisposed = false;
callback.start_accept_by_winapi();
}
void completeio_server_manager::start_receive()
{
brunning = TRUE;
bdisposed = false;
callback.start_receive();
}
int main()
{
completeio_server_manager csm;
csm.start_accept();
csm.start_receive();
printf("服务器启动成功。按任意键关闭服务器并退出程序。\n");
getchar();
csm.shutdown();
return 0;
}