-
2006-11-27
8.2.5完成端口模型 - [winsock]
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://xingzhesun.blogbus.com/logs/3923197.html
8.2.5完成端口模型
创建完成端口对象 CreateCompletionPort(HANDLE FileHandle, HANDLE ExistingCompletionPort, DWORD CompletionKey, DWORD NumberOfConcurrentThreads);
CompletionKey:则指定要与某个特定套接字句柄关联在一起的“单句柄数据”
1.工作者线程与完成端口
StartWinsock();
//step 1
//create an IO completion port.CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0,0);
//step 2;
//Determine how many processors are on the systemGetSystemInfo(&SystemInfo);
//Step3
//create worker threads based on the number of processors available on the system .For this simple case, we create one worker thread for each processor.
for(i=0; i < SystemInfo.dwNumberOfProcessors; i++)
{
HANDLE ThreadHandle;
//create a server worker thread and pass the completion port to the thread, Note:the ServerWorkerThread procedure is not defined in this listing.
ThreadHandle = CreateThread(NULL, 0, ServerWorkerThread, CompletionPort,0, &ThreadID);//close the thread handle
CloseHandle(ThreadHandle);
}//step 4
//create a listening socket
Listen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(5150);
bind(Listen, (PSOCKADDR)&InternetAddr, sizeof(InternetAddr));//prepare socket for listening
listen(Listen, 5);while (TRUE)
{
//step 5
//Accept connections and assign to completion port.
Accept = WSAAccept(Listen, NULL, NULL, NULL, 0);//step 6
//create per-handle data information structure to associate with the socket
PerHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));printf("Socket number %d connected\n",Accept);
PerHandleData->Socket = Accept;//step 7
//Associate the accepted socket with the completion port.
CreateIoCompletionPort((HANDLE)Accept,CompletionPort, (DWORD)PerHandleData,0);//创建和关联的动作完成后,系统会将完成端口关联的设备句柄、完成键作为一条纪录加入到这个完成端口的设备列表中。如果你有多个完成端口,就会有多个对应的设备列表。如果设备句柄被关闭,则表中自动删除该纪录。
//step 8
//start processing IO on the accepted socket. post oen or more WSASend() or WSARecv() calls on the socket using overlapped IO
WSARecv(...)''
}2.完成端口和重叠IO
需要由我们的应用程序负责在以后的某个时间,通过一个OVERLAPPED结构,来接收调用的结果。
BOOL GetQueuedCompletionStatus(HANDLE CompletionPort, LPDWORD lpNumberOfBytesTransferred, LPDWORD lpCompletionKey, LPOVERLAPPED* lpOverlapped, DWORD dwMilliseconds);3.单句柄数据和单IO操作数据
typedef struct
{
OVERLAPPED Overlapped;
WSABUF DataBuf;
CHAR Buffer[DATA_BUFSIZE];
bool OperationType;
} PER_IO_OPERATION_DATA;DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID)
{
HANDLE CompletionPort = (HANDLE).CompletionPortID;
DWORD ByteTransferred;
LPOVERLAPPED Overlapped;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
DWORD SendBytes, RecvBytes;
DWORD Flags;while (TRUE)
{
//Wait for IO to complete on any socket associated with the completion port
GetQueuedCompletionStatus(CompletionPort,&ByteTransferred, (LPDWORD)&PerHandleData,(LPOVERLAPPED*)&PerIoData, INFINITE);//socket and clean up the per-handle data and per-io opertion data associated with the socket
if (BytesTransferred ==0&&(PerIoData->OperationType == RECV_POSTED||PerHandleData->OperationType == SEND_POSTED))
{
//A zero bytesTransferred indicates that the socket has been closed by the peer, so you should close the socket.
//Note: Per-handle data was used to reference the socket associated withe IO operation.
closesocket(PerHandleData->Socket);GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
}//service the completed IO request, You can determine which IO request has just completed by looking at the OperationType field contained in the
//the per-io operation data.
if (PerIoData->OperationType==RECV_POSTED)
{
//Do sth with the received data in perIoData->Buffer
}//post another WSASend or WSARecv operation .
//As an example , we will post another WSARecv() IO operationFlags = 0;
//Set up the per-IO operation data for the next overlapped call
ZeroMemory(&(PerIoData->Overlapped),sizeof(OVERLAPPED));PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;
PerIoData->OperationType = RECV_POSTED;WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf),1,&RecvBytes, &Flags, &(PerIoData->Overlapped),NULL);
}
}如何正确地关闭IO端口-特别是同时运行一个或者多个线程,在几个不同的套接字上执行IO操作的时候,要避免的一个重要的问题是在进行重叠IO操作的同时,
强行释放一个OVERLAPPED结构。要想避免出现这种情况,最好的办法是针对每个套接字句柄,调用closesocket,任何尚未进行的重叠IO操作都会完成。
一旦所有套接字句柄都已经关闭,便需在完成端口上终止所有的工作者者线程的运行,PostQueuedCompletionStatus.随机文章:
Windows网络编程经验小结 2007-02-05只能在堆上实例化的类 2007-01-148.2.3WSAEventSelect 2006-11-27第7章 Winsock基础 2006-11-24第六章 地址家族和名字解析 2006-11-20
收藏到:Del.icio.us








