WinSock完成端口IO模型.doc_第1页
WinSock完成端口IO模型.doc_第2页
WinSock完成端口IO模型.doc_第3页
WinSock完成端口IO模型.doc_第4页
WinSock完成端口IO模型.doc_第5页
已阅读5页,还剩2页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

关于重叠I/O,参考WinSock重叠I/O模型;关于完成端口的概念及内部机制,参考译文深度探索I/O完成端口。完成端口对象取代了WSAAsyncSelect中的消息驱动和WSAEventSelect中的事件对象,当然完成端口模型的内部机制要比WSAAsyncSelect和WSAEventSelect模型复杂得多。IOCP内部机制如下图所示:在WinSock中编写完成端口程序,首先要调用CreateIoCompletionPort函数创建完成端口。其原型如下:WINBASEAPI HANDLE WINAPICreateIoCompletionPort(HANDLE FileHandle,HANDLE ExistingCompletionPort,DWORD CompletionKey,DWORD NumberOfConcurrentThreads );第一次调用此函数创建一个完成端口时,通常只关注NumberOfConcurrentThreads,它定义了在完成端口上同时允许执行的线程数量。一般设为0,表示系统内安装了多少个处理器,便允许同时运行多少个线程为完成端口提供服务。每个处理器各自负责一个线程的运行,避免了过于频繁的线程上下文切换。hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0)这个类比重叠I/O事件通知模型中(WSA)CreateEvent。然后再调用GetSystemInfo(&SystemInfo);取得系统安装的处理器的个数SystemInfo.dwNumberOfProcessors,根据CPU数创建线程池,在完成端口上,为已完成的I/O请求提供服务。一般线程池的规模,即线程数 = CPU数*2+2。下面的代码片段演示了线程池的创建。/ 创建线程池,规模为CPU数的两倍for(int i = 0; i Socket = AcceptSocket;CreateIoCompletionPort(HANDLE) AcceptSocket, hCompletionPort, (DWORD) PerHandleData, 0) 这个类比重叠I/O事件通知模型中设置(WSA)OVERLAPPED结构中的hEvent字段,使一个事件对象句柄同一个文件/套接字关联起来。将套接字句柄与一个完成端口关联在一起后,便可以套接字句柄为基础,投递发送与接收请求,开始对I/O请求的处理。接下来,可开始依赖完成端口,来接收有关I/O操作完成情况的通知。从本质上说,完成端口模型利用了Win32重叠I/O机制。在这种机制中,像WSARecv()和WSASend()这样的WinSock API调用会立即返回。此时,需要由我们的应用程序负责在以后的某个时间,通过一个OVERLAPPED结构,来接收调用的结果。在完成端口模型中,要想做到这一点,工作者线程WorkerThread需要调用GetQueuedCompletionStatus函数,在完成端口上等待。GetQueuedCompletionStatus函数原型如下:WINBASEAPI BOOL WINAPIGetQueuedCompletionStatus(HANDLE CompletionPort,LPDWORD lpNumberOfBytesTransferred,LPDWORD lpCompletionKey,LPOVERLAPPED *lpOverlapped,DWORD dwMilliseconds );When you perform an input/output operation with a file handle that has an associated input/output completion port, the I/O system sends a completion notification packet to the completion port when the I/O operation completes. The completion port places the completion packet in a first-in-first-out queue. The GetQueuedCompletionStatus function retrieves these queued completion packets. MSDN这个类比重叠I/O事件通知模型中的WSAWaitForMultipleEvents/WSAGetOverlappedResult获得I/O操作结果。参数一为创建线程池时传递的参数hCompletionPort,参数二提供一个DWORD指针,用来接收当I/O完成时实际传输的字节数。参数三即第二次调用CreateIoCompletionPort时传入的单句柄完成键,这里用于确定与CompletionPort绑定的具体哪个(套接字)句柄完成了I/O操作导致该函数返回。参数四即第二次调用CreateIoCompletionPort时传入的(套接字)句柄(AcceptSocket)投递重叠I/O请求(WSARecv/WSASend)时指定的(WSA)OVERLAPPED结构。实际操作中往往提供一个(WSA)OVERLAPPED扩展结构,这就是常说的“单I/O数据”。一种定义如下:typedef structOVERLAPPED Overlapped;WSABUF DataBuf;CHAR BufferDATA_BUFSIZE;DWORD BytesSEND;DWORD BytesRECV;OVERLAPPEDPLUS,PER_IO_OPERATION_DATA,*LPPER_IO_OPERATION_DATA;这里的最后两个参数BytesSEND和BytesRECV与GetQueuedCompletionStatus函数返回时的ByteTransfered参数一起同步收发操作。一般在调用CreateIoCompletionPort将套接字句柄与完成端口hCompletionPort关联后,还需要为AcceptSocket创建PerIOData,以便为后面调用WSARecv()/WSASend()提供(WSA)OVERLAPPED结构和缓冲区。为确保单I/O数据的生存周期延续到I/O完成,一般动态分配,待I/O完成再回收。对于I/O频繁的系统,则可以使用内存池,每次只是回收到空闲池,最后再真正释放。这样,可避免频繁的内存分配。可参考MFC基于CPlex结构的内存池化管理。下面的是Accept返回,调用CreateIoCompletionPort之后的代码片段。ZeroMemory(&(PerIoData-Overlapped), sizeof(OVERLAPPED);PerIoData-BytesSEND = 0;PerIoData-BytesRECV = 0;PerIoData-DataBuf.len = DATA_BUFSIZE;PerIoData-DataBuf.buf = PerIoData-Buffer;然后调用WSARecv,投递一个等待接收数据的I/O请求。WSARecv(AcceptSocket, &(PerIoData-DataBuf), 1, &RecvBytes, &Flags, &(PerIoData-Overlapped), NULL)注意参数一、参数二和参数六,实际上完成了每个AcceptSocket与PerIoData的捆绑。由于调用CreateIoCompletionPort将套接字句柄与完成端口hCompletionPort关联起来了,所以针对AcceptSocket这个套接字句柄上的I/O请求(WSARecv)完成时,一个完成通知包将被投递到完成端口hCompletionPort消息队列中。GetQueuedCompletionStatus函数是用来获取排队完成状态,它使调用线程挂起,直到收到一个完成通知包才返回。If the function dequeues a completion packet for a successful I/O operation from the completion port, the return value is nonzero. The function stores information in the variables pointed to by the lpNumberOfBytesTransferred, lpCompletionKey, and lpOverlapped parameters. If *lpOverlapped is NULL and the function does not dequeue a completion packet from the completion port, the return value is zero. The function does not store information in the variables pointed to by the lpNumberOfBytesTransferred and lpCompletionKey parameters. MSDN在工作者线程WorkerThread中调用GetQueuedCompletionStatus: while(TRUE)GetQueuedCompletionStatus(CompletionPort, &BytesTransferred, (LPDWORD)&PerHandleData, (LPOVERLAPPED *) &PerIoData, INFINITE)if (BytesTransferred = 0) / 出错 printf(Closing socket %d/n, PerHandleData-Socket);if (closesocket(PerHandleData-Socket) = SOCKET_ERROR)printf(closesocket() failed with error %d/n, WSAGetLastError();return 0;GlobalFree(PerHandleData);GlobalFree(PerIoData);continue;/ 根据lpNumberOfBytesTransferred, lpCompletionKey, and lpOverlapped参数进行处理/ 给GetQueuedCompletionStatus传递的参数三将PerIOData强制转换为(LPOVERLAPPED *) 结构,后面又要配合使用PerIOData的其他字段,这体现了“扩展”二字的用意。若GetQueuedCompletionStatus返回FALSE,可以调用(WSA)GetOverlappedResult/(WSA)GetLastError获知具体错误。如前面所言,完成端口模型利用了Win32重叠I/O机制,它是在利用完成端口队列对象来管理线程池。下面总结一下编写基于完成端口的Winsock服务器程序的要点。(1)首先,当然要调用CreateIoCompletionPort创建一个完成端口,一般一个应用程序只创建一个完成端口。(2)然后,创建一个线程池,把完成端口作为参数传给线程参数,以使工作线程调用GetQueuedCompletionStatus在完成端口上等待I/O完成,收到完成通知后提供I/O数据处理服务。(3)每当Accept(Ex)成功返回后,调用CreateIoCompletionPort将AcceptSocket与完成端口关联起来,并传递AcceptSocket的上下文信息(即“单句柄数据”)给完成键参数。同时为AcceptSocket创建一个I/O缓冲区(即“单I/O数据”,扩展OVERLAPPED结构)。(4)接着,AcceptSocket调用异步I/O操作函数,如WSARecv和WSASend,抛出重叠的I/O请求。这时需要将单I/O数据的第一个字段OVERLAPPED结构传递给WSARecv和WSASend,以表示它们投递的是“重叠”的I/O请求,需要等待系统的I/O完成通知。(5)至此,当上一步抛出的重叠I/O操作完成时,完成端口上会有一个完成通知包,工作线程收到完成通知,从GetQueuedCompletionStatus返回。通过完成键即单句柄数据提供的客户套接字上下文信息、重叠结构参数以及实际I/O的字节数,就可以正式提供I/O数据服务了。简言之,涉及两个重要的数据结构:“单句柄数据”和“单I/O数据”(扩展的OVERLAPPED结构);涉及两个重要的API: CreateIoCompletionPort和GetQueuedCompletionStatus;当然,不要忘记重叠请求的投递者WSARecv和WSASend,它们是导火索通信程序的本质工作就是“通信”。因为完成端口模型本质上利用了Win32重叠I/O机制,故(扩展的)OVERLAPPED结构提供的沟通机制依然是数据通信重要的线索。另外,要理解完成端口内部机制和工作原理及其在通信中的作用。下面补充完成端口的项目应用实例。Windows下的IIS采用了完成端口模型,参考完成端口与高性能服务器程序开发、I/O完成端口(Windows核心编程)、A simple application using I/O Completion Ports and WinSock。Apache Httpd/httpd/server/mpm/winnt/child.c中的winnt_accept()(AcceptEx)和winnt_get_connection()使用了完成端口ThreadDispatchIOCP,但并没有关联套接字,而是自己构造完成包(mpm_post_completion_contextPostQueuedCompletionStatus),完成键为枚举io_state_e,单句柄为PCOMP_CONTEXT。/ Apache Httpd/httpd/server/mpm/winnt/mpm_winnt.htypedef enum IOCP_CONNECTION_ACCEPTED = 1,IOCP_WAIT_FOR_RECEIVE = 2,IOCP_WAIT_FOR_TRANSMITFILE = 3,IOCP_SHUTDOWN = 4 io_state_e;Apache源码中只使用到IOCP_CONNECTION_ACCEPTED和IOCP_SHUTDOWN两种状态。除此之外,Apache里面没有真正的完成端口成分,ntmpm似乎依然是线程池加进程池来处理。具体I/O过程参考Apache源码Apache Httpd/httpd-2.2.15/srclib/apr/file_io/win32/readwrite.c和Apache Httpd/httpd/srclib/apr/network_io/win32/sendrecv.c。N

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论