小弟刚学的IOCP,最近在看《Networking Programming for Microsoft Windows》,其中里面说道
 “当与一个完成端口相关的文件句柄上启动的异步IO操作完成时,一个IO完成包就会进入到该完成端口的队列中。”
我的问题是:
1.这个完成包应该是系统自己投递到完成队列当中的,是吗?
2.对这个完成包要怎么处理?我知道要在线程里调用GetQueuedCompletionStatus函数获取完成包,但接下来呢?在这个完成包里系统是不是会设置一个参数用来指定本次完成的操作类型还是怎么回事?
看了些资料还是一头雾水啊。请各位高手不吝赐教。

解决方案 »

  1.   

    1.完成包是要你自己投入队列的,具体的就是 WSARecv 实际就是投递了一个IO请求,并且你需要自己准备缓冲区,当IO操作完成时,系统将这个包移动到完成端口队列,所以你才会 GetQueueXXX 那个函数获取到。2.接下来你就需要访问缓冲区噻,其实完成端口不止可以用于网络,理论上可以用于所有IO操作相关的地方,但是就事论事来说,GetQueueXXX 以后你需要做的就是从缓冲区得到接受到的数据,并且做出处理,例如查询数据库,写入文件等等。给你备注下,最近看到好多人问IOCP的问题:完成端口为什么会有个 OpCode 这个是另外一个朋友的一个问题。
    这句话说的很好,比如 WSASend, WSARecv, 包括 CancelIO, 等等函数,都是触发IO操作,要明白IO操作就是输入输出操作。那么为什么要一个 OpCode ,以为只要是触发了IO的操作都会让 GetQueueXXX 返回,但是我们实际上只需要的是 Recv 操作,以为这个是我们关注的,而 Send 操作其实对于我们来说可能没什么用,但是如何区分,就是靠GetQueueXX的 Overlapped 这个值,其实这个值是我们传递过去的,是一个指针,WSARecv,WSASend都有这个参数,实际 GetQueue得到的这个值就是 WSARecv设置的OVERLAPPED指针,一般的方法就是将这个指针扩展下,除了标准的 overlapped 另外加一个我们需要的信息,就是所谓的 opcode 这样我们就可以判断出 getqueue 返回的到底是发送,还是接收 消息,或者其他消息。
    另外一个问题:为什么完成端口效率比较高。其实完成端口的核心思想就是队列化,一般来说线程数量=处理器数量X2,也就是说,比如一般服务器是4个CPU,按每个都是双核算,就是8个核心,就是16个线程,这样,当同时的消息比较少的时候,我们只有几个线程在工作。不会占用过多的CPU,但是当网络流量很大的时候,当16个线程都在工作的时候。如果另外有请求出现,完成端口的作用就显现出来了,完成端口会将剩下的请求排成一个队列,也就是排队处理,这样在不过度消耗CPU和内存的情况下,最大效率的处理请求,这个就是完成端口。其实高级的完成端口设计实际还是使用了线程池,内存池等技术,网上有很多成熟的IOCP类,用起来很方便的,我常用的IOCP类就是自己在 gh0st 的IOCP类基础上改的,自己写着玩还行,反正我不是做服务器开发的。
      

  2.   

    谢谢xfill,看了有茅塞顿开的感觉。不过还有一点问题:上面说通过扩展overlapped结构我们可以传递一些有关操作的信息,但是overlapped本身这个结构有什么用?我们对这个结构要进行什么操作呢?谢谢谢谢!
      

  3.   

    Overlapped 是异步操作用的。你可以看下MSDN这个结构体的结构typedef struct _OVERLAPPED {
      ULONG_PTR Internal; 
      ULONG_PTR InternalHigh; 
      DWORD Offset; 
      DWORD OffsetHigh; 
      HANDLE hEvent; 
    } OVERLAPPED; Members
    Internal 
    Not used. 
    InternalHigh 
    Not used. 
    Offset 
    File offset of the beginning of the lock range. 
    OffsetHigh 
    High order word of the byte offset of the beginning of the lock range. 
    hEvent 
    Not used. 前两个未使用,3,4 个分别表示IO操作的偏移,这个一般用在异步写文件的时候,写入文件的偏移位置HANDLE hEvent; 是最重要的,就是一个 Event 句柄,IO操作完成以后系统会 SetEvent 来设置这个 event 返回,一般通过等待WaitForSingleObject(ol->hEvent, ...); 可以等待IO操作完成。一般系统内只要涉及到IO异步的都会用到这个结构体。你不需要对他进行什么操作,因为函数需要传递一个 overlapped 结构的指针,而 GetQueue 收到的也是这个指针,那么就可以通过这个指针,传递一些我们需要的信息。
      

  4.   

    嗯,总算有点眉目了,谢谢xfill的热心帮助。谢谢。