#include <WINSOCK2.H>
#include <stdio.h>#define PORT 5150
#define MSGSIZE 1024#pragma comment(lib, "ws2_32.lib")typedef enum
{
RECV_POSTED
}OPERATION_TYPE;typedef struct
{
WSAOVERLAPPED overlap;
WSABUF Buffer;
char szMessage[MSGSIZE];
DWORD NumberOfBytesRecvd;
DWORD Flags;
OPERATION_TYPE OperationType;
}PER_IO_OPERATION_DATA, *LPPER_IO_OPERATION_DATA;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;
SYSTEM_INFO systeminfo;
LPPER_IO_OPERATION_DATA lpPerIOData = NULL;// Initialize Windows Socket library
WSAStartup(0x0202, &wsaData);// Create completion port
CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);// Create worker thread
GetSystemInfo(&systeminfo);
for (i = 0; i < systeminfo.dwNumberOfProcessors; i++)
{
CreateThread(NULL, 0, WorkerThread, CompletionPort, 0, &dwThreadId);
}// Create listening socket
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);// Bind
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
listen(sListen, 3);while (TRUE)
{
// Accept a connection
sClient = accept(sListen, (struct sockaddr *)&client, &iaddrSize);
printf("Accepted client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port)); // Associate the newly arrived client socket with completion port
CreateIoCompletionPort((HANDLE)sClient, CompletionPort, (DWORD)sClient, 0);
// Launch an asynchronous operation for new arrived connection
lpPerIOData = (LPPER_IO_OPERATION_DATA)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(PER_IO_OPERATION_DATA));
lpPerIOData->Buffer.len = MSGSIZE;
lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
lpPerIOData->OperationType = RECV_POSTED;
WSARecv(sClient,
&lpPerIOData->Buffer,
1,
&lpPerIOData->NumberOfBytesRecvd,
&lpPerIOData->Flags,
&lpPerIOData->overlap,
NULL);
}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;while (TRUE)
{
GetQueuedCompletionStatus(
CompletionPort,
&dwBytesTransferred,
&sClient,
(LPOVERLAPPED *)&lpPerIOData,
INFINITE);
if (dwBytesTransferred == 0xFFFFFFFF)
{
return 0;
}
if (lpPerIOData->OperationType == RECV_POSTED)
{
if (dwBytesTransferred == 0)
{
// Connection was closed by client
closesocket(sClient);
HeapFree(GetProcessHeap(), 0, lpPerIOData);
}
else
{
lpPerIOData->szMessage[dwBytesTransferred] = '\0';
send(sClient, lpPerIOData->szMessage, dwBytesTransferred, 0);
// Launch another asynchronous operation for sClient
memset(lpPerIOData, 0, sizeof(PER_IO_OPERATION_DATA));
lpPerIOData->Buffer.len = MSGSIZE;
lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
lpPerIOData->OperationType = RECV_POSTED;
WSARecv(sClient,
&lpPerIOData->Buffer,
1,
&lpPerIOData->NumberOfBytesRecvd,
&lpPerIOData->Flags,
&lpPerIOData->overlap,
NULL);
}
}
}
return 0;
}本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/byxdaz/archive/2008/03/02/2139515.aspx
上面的代码是完成端口模型的简单实现代码,在主函数里有个while循环,里面有个WSARecv函数,在线程函数里也有一个,如果有客户端发送信息给服务器,是在哪个WSARecv接收到的?多谢指导。
#include <stdio.h>#define PORT 5150
#define MSGSIZE 1024#pragma comment(lib, "ws2_32.lib")typedef enum
{
RECV_POSTED
}OPERATION_TYPE;typedef struct
{
WSAOVERLAPPED overlap;
WSABUF Buffer;
char szMessage[MSGSIZE];
DWORD NumberOfBytesRecvd;
DWORD Flags;
OPERATION_TYPE OperationType;
}PER_IO_OPERATION_DATA, *LPPER_IO_OPERATION_DATA;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;
SYSTEM_INFO systeminfo;
LPPER_IO_OPERATION_DATA lpPerIOData = NULL;// Initialize Windows Socket library
WSAStartup(0x0202, &wsaData);// Create completion port
CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);// Create worker thread
GetSystemInfo(&systeminfo);
for (i = 0; i < systeminfo.dwNumberOfProcessors; i++)
{
CreateThread(NULL, 0, WorkerThread, CompletionPort, 0, &dwThreadId);
}// Create listening socket
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);// Bind
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
listen(sListen, 3);while (TRUE)
{
// Accept a connection
sClient = accept(sListen, (struct sockaddr *)&client, &iaddrSize);
printf("Accepted client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port)); // Associate the newly arrived client socket with completion port
CreateIoCompletionPort((HANDLE)sClient, CompletionPort, (DWORD)sClient, 0);
// Launch an asynchronous operation for new arrived connection
lpPerIOData = (LPPER_IO_OPERATION_DATA)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(PER_IO_OPERATION_DATA));
lpPerIOData->Buffer.len = MSGSIZE;
lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
lpPerIOData->OperationType = RECV_POSTED;
WSARecv(sClient,
&lpPerIOData->Buffer,
1,
&lpPerIOData->NumberOfBytesRecvd,
&lpPerIOData->Flags,
&lpPerIOData->overlap,
NULL);
}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;while (TRUE)
{
GetQueuedCompletionStatus(
CompletionPort,
&dwBytesTransferred,
&sClient,
(LPOVERLAPPED *)&lpPerIOData,
INFINITE);
if (dwBytesTransferred == 0xFFFFFFFF)
{
return 0;
}
if (lpPerIOData->OperationType == RECV_POSTED)
{
if (dwBytesTransferred == 0)
{
// Connection was closed by client
closesocket(sClient);
HeapFree(GetProcessHeap(), 0, lpPerIOData);
}
else
{
lpPerIOData->szMessage[dwBytesTransferred] = '\0';
send(sClient, lpPerIOData->szMessage, dwBytesTransferred, 0);
// Launch another asynchronous operation for sClient
memset(lpPerIOData, 0, sizeof(PER_IO_OPERATION_DATA));
lpPerIOData->Buffer.len = MSGSIZE;
lpPerIOData->Buffer.buf = lpPerIOData->szMessage;
lpPerIOData->OperationType = RECV_POSTED;
WSARecv(sClient,
&lpPerIOData->Buffer,
1,
&lpPerIOData->NumberOfBytesRecvd,
&lpPerIOData->Flags,
&lpPerIOData->overlap,
NULL);
}
}
}
return 0;
}本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/byxdaz/archive/2008/03/02/2139515.aspx
上面的代码是完成端口模型的简单实现代码,在主函数里有个while循环,里面有个WSARecv函数,在线程函数里也有一个,如果有客户端发送信息给服务器,是在哪个WSARecv接收到的?多谢指导。
我是认为主线程和工作线程应该都是同时在运行的么,那么客户端发送的信息到底是被哪个WSARecv接收到的?或者说主线程里的那个WSARecv函数是用来做什么用的,因为线程函数里已经有了接收到函数了啊?
多谢指导
如果没有主线程的WSARecv异步调用,就不会使工作线程的GetQueuedCompletionStatus函数返回.在主线程里发出一个异步接收调用,当在此套接字上第一次有数据到达并接收完毕时,将会激活等待函数GetQueuedCompletionStatus.注意一个地方:在PER_IO_OPERATION_DATA结构中,WSAOVERLAPPED结构是放在最前面的.而在主线程中,将lpPerIOData->overlap的地址传给了WSARecv函数.所以在工作线程中,GetQueuedCompletionStatus函数中返回的WSAOVERLAPPED结构的地址将是主线程传给WSARecv函数的lpPerIOData->overlap的地址.而overlap是PER_IO_OPERATION_DATA结构的第一个成员,所以GetQueuedCompletionStatus函数中返回的WSAOVERLAPPED结构的地址将是主线程中存放接收到的数据的内存地址.因此可以对数据进行处理.
第一次以后,就是工作线程的WSARecv函数接收数据了.我没有对楼主的代码编译验证我的想法.有理解不对的地方,还请各位不吝指教.
真正的接收都是后台overlap完成的
而GetQueuedCompletionStatus就是捕获这个完成事件不管你在哪里投递IO请求,最终都是工作线程的GetQueuedCompletionStatus中捕获
假如你将所有的投递动作都放在GetQueuedCompletionStatus之后,那么它们永远不会被执行到主线程中的投递,正是为了让GetQueuedCompletionStatus跑起来
投递AcceptEx我有在看
是不合适我这样的新手使用
复杂度太高
非也,在IOCP中,WSARecv和WSASend并不会接收或发送
他们仅仅只是“投递”接收或发送的请求所谓的投递WSARecv,就是调用WSARecv时,传入了有效的overlapped参数,WSARecv检测到overlapped参数不为NULL,就不会进行IO操作,而会将IO操作投递到完成端口