创建IOCP程序,一般的步骤

 

1.       创建一个单句柄数据结构体,该结构体里一般都包含一个套接字数据。因为IOCP实际上会有固定的几个线程(工作线程),这些线程在IOCP结果队列里查询IO操作结果。这些结果不止是在一个套接字上进行的操作(读或写),而是包括了所有与该IOCP对象关联起来的套接字上的操作结果。因此,为了区分某次操作结果属于哪个套接字,就需要这个单句柄数据结构里包含这个套接字句柄。

2.       创建一个以OVERLAPPED为首个元素的数据结构体。该结构体实际上对应着一个IO操作(例如WSASend)。对于 WSASend, WSARecv以及查询操作结果函数都需要一个OVERLAPPED参数(一般是指针),通常情况下我们需要更多的数据,因此定义的这个结构体里通常包含了更多的数据(例如WSABUF,它可以用来容纳WSARecv接受到的数据)。之所以要把OVERLAPPED 作为这个结构体的第一个元素,是为了在使用查询函数GetQueuedCompletionStatus后,可以通过该函数返回的OVERLAPPED类型的指针得到我们这里定义的结构体对象地址,从而获取更多的数据。

3.       每一次接受到新的连接时(accept),都将这个新的套接字与完成端口相关联。并且创建一个单句柄对象(也就是完成键)。每一个套接字都有一个关联的单句柄对象。而每一个IO操作都有一个关联的OVERLAPPED相关的数据结构(上一步定义的结构体)。

4.       可以在任何时候提交异步IO请求,例如WSASend, WSARecv。这里需要为OVERLAPPED相关的结构体指定操作类型。一个典型的结构体为(即第二步定义的结构体):

              struct IOContext
{
              /// 很多函数需要此参数
              OVERLAPPED ol;
              /// 存放接受数据
              char buf[MAX_BUF];
              ///
              WSABUF wsabuf;
              /// 操作类型,提交IO操作时指定该值,在查询操作结果时,可以重新获取到该值
              int op_type;
};
在创建该结构体的变量时,为op_type指定一个值。然后将此结构体的地址给WSASend之类的函数。在工作者线程中执行查询时,实际上得到了该结构体的地址(结构体变量),那么,就可以获取op_type的值。
注意:查询结构只能获取IO操作的字节数(以及IO操作结果数据),不能知道IO操作的类型。所以IO操作的类型实际上是在这里用户自己指定的。
当执行WSASend时,设置op_type为SEND(自己定义的常量),执行WSARecv时,指定READ。然后在查询结果时,可以根据op_type知道这个操作结果是什么类型。如果是SEND,那么就表示之前提交的WSASend操作。
IOCP是一个异步操作机制,之所以是异步,就是因为可以随时提交IO操作。提交之后具体的操作由系统为你完成。完成后就需要某种机制来得知操作结果。IOCP设置的这个结果队列就是一种机制。
5.       可以通过PostQueuedCompletionStatus手动地往结果队列里放置一个操作结果。通常这个函数都用于让工作者线程退出。例如:

                   PostQueuedCompletionStatus( cp_handle, 0, NULL, NULL );
然后在工作者线程里:

         ret = GetQueuedCompletionStatus( cp_handle, &transfer_bytes, (PULONG_PTR) &hc,
              (LPOVERLAPPED*)&ic, INFINITE );
         if( ic == NULL )
         {
              printf( "ic == NULL\n" );
              /*
                   使用PostQueuedCompletionStatus传递过来的数据,
                   这里约定ic==NULL时退出
              */
              break;
         }
        
6.     如果不提交任何IO操作,那么结果队列里很有可能一直都是空的。那么GetQueued这个查询函数就会一直得不到数据。
 
7.     纵观IOCP程序,一个比较复杂的地方在于资源的释放。在接收到一个新的连接时,会为这个连接创建单句柄数据,执行IO操作的话,还要创建OVERLAPPED相关结构体变量。这些变量的地址都会在工作者线程中通过GetQueued..函数获取,并在工作者线程中使用。一个比较直接的做法是在工作者线程中释放这些资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值