完成端口模型学习

来源:互联网 发布:淘宝上的猛犸象牙真吗? 编辑:程序博客网 时间:2024/05/16 11:48

  “完成端口”模型是迄今为止最为复杂的一种I / O模型。然而,假若一个应用程序同时需要管理为数众多的套接字,那么采用这种模型,往往可以达到最佳的系统性能!但不幸的是,该模型只适用于Windows NT和Windows 2000以上的操作系统。因其设计的复杂性,只有在你的应用程序需要同时管理数百乃至上千个套接字的时候,而且希望随着系统内安装的C P U数量的增多,应用程序的性能也可以线性提升,才应考虑采用“完成端口”模型。要记住的一个基本准则是,假如要为Windows NT或Windows 2000开发高性能的服务器应用,同时希望为大量套接字I / O请求提供服务(We b服务器便是这方面的典型例子),那么I / O完成端口模型便是最佳
选择!
      从本质上说,完成端口模型要求我们创建一个Wi n 3 2完成端口对象,通过指定数量的线程,对重叠I / O请求进行管理,以便为已经完成的重叠I / O请求提供服务。要注意的是,所谓“完成端口”,实际是Wi n 3 2、Windows NT以及Windows 2000采用的一种I / O构造机制,除套接字句柄之外,实际上还可接受其他东西。然而,下面打算讲述如何使用套接字句柄,来发挥完成端口模型的巨大威力。使用这种模型之前,首先要创建一个I / O完成端口对象,用它面向任意数量的套接字句柄,管理多个I / O请求。要做到这一点,需要调用CreateCompletionPort函数。
该函数定义如下:

WINBASEAPI
__out
HANDLE
WINAPI
CreateIoCompletionPort(
    __in     HANDLE FileHandle,
    __in_opt HANDLE ExistingCompletionPort,
    __in     ULONG_PTR CompletionKey,
    __in     DWORD NumberOfConcurrentThreads
    );

在我们深入探讨其中的各个参数之前,首先要注意该函数实际用于两个明显有别的目的:
■ 用于创建一个完成端口对象。
■ 将一个句柄同完成端口关联到一起。

最开始创建一个完成端口时,唯一感兴趣的参数便是NumberofConcurrentThreads(并发线程的数量);前面三个参数都会被忽略。 NumberofConcurrentThreads参数的特殊之处在于,它定义了在一个完成端口上,同时允许执行的线程数量。理想情况下,我们希望每个处理器各自负责一个线程的运行,为完成端口提供服务,避免过于频繁的线程“场景”切换。若将
该参数设为0,表明系统内安装了多少个处理器,便允许同时运行多少个线程!可用下述代码创建一个I / O完成端口:

   m_hCompletionPort = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0);

 

成功创建一个完成端口后,便可开始将套接字句柄与对象关联到一起。但在关联套接字之前,首先必须创建一个或多个“工作者线程”,以便在I / O请求投递给完成端口对象后,为完成端口提供服务。通过研究,线程数需要大于dNumberofConcurrentThreads参数,我们可以创建2倍NumberofConcurrentThreads的线程。

      一旦在完成端口上拥有足够多的工作者线程来为I / O请求提供服务,便可着手将套接字句柄同完成端口关联到一起。刚才不是用CreateIoCompletionPort创建了一个完成端口吗?现在我们用相同的函数讲套接字绑定在该完成端口上,只是传入的参数变了,如下:

 

       CreateIoCompletionPort((HANDLE)scClient, //指定一个要同完成端口关联在一起的套接字句柄 

                                            m_hCompletionPort, //前面已经创建的的完成端口对象
                                            (DWORD)pIOCPSocket,//传送给处理函数的参数,也就是和一个指定套接字相关的指针类型
                                             0)

     其实完成端口是一个队列,所有的线程都在等消息出现,如果队列里有消息,就每个线程去获取一个消息执行它。先用函数CreateIoCompletionPort来创建一个消息队列,然后使用GetQueuedCompletionStatus函数来从队列获取消息,使用函数PostQueuedCompletionStatus来向队列里发送消息,通过这三个函数就实现完成端口的消息循环处理。上面我们已经建立好了队列,现在就要向队列发送消息了:

       WINBASEAPI
       BOOL
       WINAPI
     PostQueuedCompletionStatus(
       __in     HANDLE CompletionPort,                       //向那个完成端口发送消息
       __in     DWORD dwNumberOfBytesTransferred,//传送了多少个字节
       __in     ULONG_PTR dwCompletionKey,             //传送给处理函数的参数(套接字指针)
       __in_opt LPOVERLAPPED lpOverlapped            //传送给处理函数的一个OverLappeed结构
    );

 

    列表有了,消息也发了,我们就可以接受消息并处理了,这需要在线程里面做这些处理:

       WINBASEAPI
       BOOL
       WINAPI
       GetQueuedCompletionStatus(
           __in HANDLE CompletionPort,                            //从哪个完成端口接受消息
           __out LPDWORD lpNumberOfBytesTransferred, //传送了多少个字节
           __out PULONG_PTR lpCompletionKey,               //输出的参数(套接字指针) 
           __out LPOVERLAPPED *lpOverlapped,               //输出的OverLappeed结构
           __in DWORD dwMilliseconds                              //等待时间
    );

 

 

     获得了消息和输出的参数,我们就可以做对应的一系列处理了。

原创粉丝点击