本篇文章会接上一篇,完成 重叠I/O 模型

重叠模型是让应用程序使用重叠数据结构(WSAOVERLAPPED),一次投递一个或多个 WinSock I/O请求。针对这些请求,在它们完成后,应用程序会受到通知,于是就可以通过另外的代码来处理这些数据了。

有两种方法可以用来管理重叠I/O请求完成的情况 – 即接到重叠操作完成的通知时处理

  1. 事件对象通知 (Event Object Notification)
  2. 完成例程(Completion Routies)

 

先讲事件对象通知吧。

基于事件通知的方法,就是要将WinSock事件对象与WSAOVERLPPED结构关联在一起,在使用重叠结构的情况下,我们常用的 send,sendto,recv,recvfrom 也要被WSASend,WSASendto,WSARecv,WSARecvfrom 替换掉了。

还是看代码吧,我尽量用代码详详细细的讲这个模型:

代码是很清晰的…主要麻烦的是各个函数的意思。

首先我们来看看重叠结构的成员吧:

上文里面,我们要关注的只有最后一个 hEvent – 事件对象句柄。

接下来是我们的一个接受函数 – 它的参数比recv函数要多,因为会用到重叠结构

七个参数:

  1. 套接字
  2. 接受缓冲区 –  这里需要一个由WSABUF结构构成的数组
  3. 数组中WSABUF结构数量
  4. 如果接收操作立即完成,这里会返回函数调用所接受到的字节数
  5. 设为0即可
  6. 绑定的重叠结构
  7. 完成例程中会用到的参数 – 设置为NULL

然后来看看等待函数 – WSAWaitForMultipleEvents

五个参数:

  1. 等待的事件总数量
  2. 事件数组的指针
  3. 设置为 TRUE,所有事件被触发的时候函数才会返回 – FALSE则任何一个事件被触发函数都要返回
  4. 超时时间 – 如果超时,返回WSA_WAIT_TIMEOUT – 如果设置为 0 ,则函数立即返回 – 如果设置为INFINITE,则只有某一事件触发后才会返回。
  5. 先设置为FALSE

返回值:

WSA_WAIT_TIMEOUT :最常见的返回值,我们需要做的就是继续Wait

WSA_WAIT_FAILED : 出现了错误,请检查cEvents和lphEvents两个参数是否有效

WSAWaitForMultipleEvents函数只能支持由WSA_MAXIMUM_WAIT_EVENTS对象定义的一个最大值,是 64,就是说WSAWaitForMultipleEvents只能等待64个事件,如果想同时等待多于64个事件,就要 创建额外的工作者线程,就不得不去管理一个线程池。

 

查询重叠操作完成的结果 – WSAGetOverlappedResult

五个参数:

  1. 套接字
  2. 重叠结构的指针
  3. 本次操作接受 – 发送的字节数
  4. 如果设置为TRUE,除非重叠操作完成,否则不会返回。如果返回False,而且操作仍处于挂起状态,那么函数就会返回FALSE…
  5. 指针 – 接收结果标志

以上就是事件对象通知的全部了:

 

接下来是完成例程的:

用 完成例程来实现重叠I/O比用事件通知简单得多。

在这个模型中,主线程只用不停的接受连接即可;

辅助线程判断有没有新的客户端连接被建立,如果有,就为那 个客户端套接字激活一个异步的WSARecv操作,然后调用SleepEx使线程处于一种可警告的等待状态,以使得I/O完成后 CompletionROUTINE可以被内核调用。如果辅助线程不调用SleepEx,则内核在完成一次I/O操作后,无法调用完成例程(因为完成例程 的运行应该和当初激活WSARecv异步操作的代码在同一个线程之内)。
完成例程内的实现代码比较简单,它取出接收到的数据,然后将数据原封不动 的发送给客户端,最后重新激活另一个WSARecv异步操作。注意,在这里用到了“尾随数据”。我们在调用WSARecv的时候,参数 lpOverlapped实际上指向一个比它大得多的结构PER_IO_OPERATION_DATA,这个结构除了WSAOVERLAPPED以外,还被我们附加了缓冲区的结构信息,另外还包括客户端套接字等重要的信息。这样,在完成例程中通过参数lpOverlapped拿到的不仅仅是 WSAOVERLAPPED结构,还有后边尾随的包含客户端套接字和接收数据缓冲区等重要信息。

大致是这样 …有问题留言就好

【WinSock】网络编程 – I/O模型(二) – 重叠I/O
Tagged on:
0 0 投票数
Article Rating
订阅评论
提醒

0 评论
内联反馈
查看所有评论