重叠I/O(Overlapped I/O)

2023-10-17 22:40
文章标签 重叠 overlapped

本文主要是介绍重叠I/O(Overlapped I/O),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转载http://t.csdn.cn/sAUoA

重叠I/O(Overlapped I/O) 
   
  在 Winsock 中,重叠 I/O(Overlapped I/O)模型能达到更佳的系统性能,高于之前讲过的三种。重叠模型的基本设计原理便是让应用程序使用一个重叠的数据结构(WSAOVERLAPPED),一次投递一个或多个 Winsock I/O 请求。针对这些提交的请求,在它们完成之后,我们的应用程序会收到通知,于是我们就可以对数据进行处理了。 
   
  套接字的重叠I/O模型才是真正意义上的异步I/O模型。在应用程序中调用输入或输出函数后,立即返回。当I/O操作完成后,系统通知应用程序。利用该模型,应用程序在调用输入或者输出函数后,只需要等待I/O操作完成的通知即可。 从发送和接收数据操作的角度看,前3个模型不是异步模型。因为在这3个模型中,I/O操作还是同步的。 重叠I/O模型才是真正意义上的异步模型。 
   
  四种模型比较: 
   
  前三个模型主要区别在第一阶段。Select模型利用select函数主动检查系统中套接字是否满足可读条件。而WSAAsyncSelect模型和WSAEventSelect模型则被动等待系统通知。当系统发生FD_READ网络事件时,WSAAsyncSelect模型以消息的形式接收通知,WSAEventSelect模型以事件形式接收通知。 
   
  在第二个阶段,前三个模型基本相同。在将数据从系统复制到用户缓冲区时,线程阻塞于函数的调用。重叠I/O模型与前3个模型不同。Windows Sockets 应用程序在调用输入函数后,只需等待接收完成系统I/O操作后发送通知。 
   
  实现方法: 
   
  要想在一个套接字上使用重叠 I/O 模型,首先必须使用 WSA_FLAG_OVERLAPPED 这个标志,创建一个套接字。例如: SOCKET s = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED); 
   
  创建套接字的时候,假如使用的是 socket 函数,那么会默认设置 WSA_FLAG_OVERLAPPED 标志。 
   
  成功建好一个套接字,同时将其与一个本地接口绑定到一起后,便可开始进行重叠 I/O 操作,为了要使用重叠结构,我们常用的 send、recv 等收发数据的函数也都要被 WSASend、WSARecv 替换掉了,方法是调用下述的 Winsock 函数,同时指定一个 WSAOVERLAPPED 结构(可选),它们的用法我后面会讲到: ■ WSASend ■ WSASendTo ■ WSARecv ■ WSARecvFrom ■ WSAIoctl ■ AcceptEx 
   
  WSA_IO_PENDING : 最常见的返回值,这是说明我们的重叠函数调用成功了,但是 I/O 操作还没有完成。 
   
  若随一个 WSAOVERLAPPED 结构一起调用这些函数,函数会立即完成并返回,无论套接字是否设为阻塞模式。 那么我们如何来得知我们的 I/O 请求是否成功了呢?方法有两个: ■ 等待“事件对象通知”; ■ 通过“完成例程”。 
   
  I/O模型实现——事件通知 
   
  重叠函数(如:WSARecv)的参数中都有一个 Overlapped 参数,我们可以假设是把我们的WSARecv这样的操作“绑定”到这个重叠结构上,提交一个请求,而不是将操作立即完成,其他的事情就交给重叠结构去做,而其中重叠结构又要与Windows的事件对象“绑定”在一起,这样我们调用完 WSARecv 以后就可以“坐享其成”,等到重叠操作完成以后,自然会有与之对应的事件来通知我们操作完成,然后我们就可以来根据重叠操作的结果取得我们想要的数据了。 
   
  WSAOVERLAPPED 结构 
   
  重叠 I/O 的事件通知方法要求将 Win32事件对象与 WSAOVERLAPPED 结构关联在一起,当 I/O 操作完成后,事件的状态会变成“有信号”状态,即激发态(是不是跟上节课给大家讲的事件选择模型很像?); 
   
  下面来看一下 WSAOVERLAPPED 结构的定义: typedef struct _WSAOVERLAPPED { 
   
  DWORD Internal; 
   
  DWORD InternalHigh; 
   
  DWORD Offset; 
   
  DWORD OffsetHigh; 
   
  WSAEVENT hEvent; 
   
  } WSAOVERLAPPED, FAR * www.senta77.com LPWSAOVERLAPPED; 
   
  其中,Internal、InternalHigh、Offset 和 OffsetHigh 字段均由系统在内部使用,不应由应用程序直接进行处理或使用。而另一方面,hEvent 字段有点儿特殊,它允许应用程序将一个事件对象句柄同一个套接字关联起来 。 
   
  大家可能会觉得奇怪,如何将一个事件对象句柄分配给该字段呢?正如我们早先在 WSAEventSelect 模型中讲述的那样,可用 WSACreateEvent 函数来创建一个事件对象句柄。一旦创建好一个事件句柄,简单地将重叠结构的 hEvent 字段分配给事件句柄,再使用重叠结构,调用一个Winsock函数即可,比如 WSASend 或 WSARecv。 
   
  一个重叠 I/O 请求最终完成后,我们的应用程序要负责取回重叠 I/O 操作的结果。一个重叠请求操作最终完成之后,在事件通知方法中,Winsock会更改与一个 WSAOVERLAPPED 结构对应的一个事件对象的事件传信状态,将其从“无信号”变成“有信号”。由于一个事件对象已分配给 WSAOVERLAPPED 结构,所以只需简单地调用 WSAWaitForMultipleEvents 函数,从而判断出一个重叠 I/O 调用在什么时候完成。 
   
  发现一次重叠请求完成之后,接着需要调用 WSAGetOverlappedResult(取得重叠结构)函数,判断那个重叠调用到底是成功,还是失败。 
   
  该函数的定义如下: BOOL WSAAPI WSAGetOverlappedResult( 
   
  __in SOCKET s, 
   
  __in LPWSAOVERLAPPED lpOverlapped, 
   
  __out LPDWORD lpcbTransfer, 
   
  __in BOOL fWait, __out LPDWORD lpdwFlags ); 
   
  s 参数用于指定在重叠操作开始的时候,与之对应的那个套接字。 
   
  lpOverlapped 参数是一个指针,对应于在重叠操作开始时,指定的那个 WSAOVERLAPPED 结构。 
   
  lpcbTransfer 参数也是一个指针,对应一个DWORD(双字)变量,负责接收一次重叠发送或接收操作实际传输的字节数 
   
  fWait 参数用于决定函数是否应该等待一次待决(未决)的重叠操作完成。若将 fWait设为 TRUE,那么除非操作完成,否则函数不会返回;若设为FALSE,而且操作仍然处于“待决”状态,那么WSAGetOverlappedResult 函数会返回 FALSE值,同时返回一个WSAIOINCOMPLETE(I/O操作未完成)错误。但就我们目前的情况来说,由于需要等候重叠操作的一个已传信事件完成,所以该参数无论采用什么设置,都没有任何效果。 
   
  参数 lpdwFlags 对应于一个指针,指向一个DWORD(双字),负责接收结果标志(假如原先的重叠调用是用WSARecv或WSARecvFrom函数发出的)。 
   
  返回值:若 WSAGetOverlappedResult 函数调用成功,返回值就是TRUE。这意味着我们的重叠 I/O 操作已成功完成,而且由 lpcbTransfer 参数指向的值已进行了更新。若返回值是FALSE.。 
   
  那么可能是由下述任何一种原因造成的: 1)、重叠 I/O操 作仍处在“待决”状态。 2)、重叠操作已经完成,但含有错误。 3)、重叠操作的完成状态不可判决,因为在提供给 WSAGetOverlappedResult函数的一个或多个参数中,存在着错误 失败后,由 lpcbTransfer 参数指向的值不会进行更新,而且我们的应用程序应调用 WSAGetLastError 函数,调查到底是何种原因造成了调用失败。 
   
  重叠 I/O 模型的编程步骤: 
   
  重叠 I/O 模型的编程步骤总结如下: 1) 创建一个套接字,开始在指定的端口上监听连接请求; 
   
  2) 接受一个客户端进入的连接请求; 
   
  3) 为接受的套接字新建一个 WSAOVERLAPPED 结构,并为该结构分配一个事件对象句柄, 同时将该事件对象句柄分配给一个事件数组,以便稍后由 WSAWaitForMultipleEvents 函数使用。 
   
  4) 在套接字上投递一个异步 WSARecv 请求,指定参数为 WSAOVERLAPPED 结构。 注意函数通常会以失败告终,返回 SOCKET_ERROR 错误状态 WSA_IO_PENDING(I/O操作尚未完成); 
   
  5) 使用步骤3)的事件数组,调用 WSAWaitForMult www.2636666.cn ipleEvents 函数,并等待与重叠调用关联在一起的事件进入“已传信”状态(换言之,等待那个事件的“触发”); 
   
  6) WSAWaitForMultipleEvents 函数返回后,针对“已传信”状态的事件,调用 WSAResetEvent(重设事件)函数,从而重设事件对象,并对完成的重叠请求进行处理; 
   
  7) 使用 WSAGetOverlappedResult 函数,判断重叠调用的返回状态是什么; 
   
  8) 在套接字上投递另一个重叠 WSARecv 请求; 
   
  9) 重复步骤5)~8)。 
   
  在 Windows NT 和 Windows 2000 中,重叠 I/O 模型也允许应用程序以一种重叠方式,实现对客户端连接的接受。 具体的做法是在监听套接字上调用 AcceptEx 函数。AcceptEx 是一个特殊的 Winsock1.1 扩展函数,位于 Mswsock.h 头文件以及 Mswsock.lib 库文件内。 
   
  AcceptEx 函数的定义如下: BOOL AcceptEx( www.furong157.com __in SOCKET sListenSocket, 
   
  __in SOCKET sAcceptSocket, 
   
  __in PVOID lpOutputBuffer, 
   
  __in DWORD dwReceiveDataLength, 
   
  __in DWORD dwLocalAddressLength, 
   
  __in DWORD dwRemoteAddressLength, 
   
  __out LPDWORD lpdwBytesReceived, 
   
  __in LPOVERLAPPED www.furggw.com/lpOverlapped ); 
   
  sListenSocket 参数指定的是一个监听套接字。 
   
  sAcceptSocket 参数指定的是另一个套接字,负责对进入连接请求的“接受”。 AcceptEx 函数和 accept 函数的区别在于,我们必须提供接受的套接字,而不是让函数自动为我们创建。 正是由于要提供套接字,所以要求我们事先调用 socket 或 WSASocket 函数,创建一个套接字,以便通过 sAcceptSocket 参数,将其传递给 AcceptEx。 
   
  lpOutputBuffer 参数指定的是一个特殊的缓冲区,因为它要负责三种数据的接收:服务器的本地地址,客户机的远程地址,以及在新建连接上发送的第一个数据块。 
   
  dwReceiveDataLength参数以字节为单位,指定了在 lpOutputBuffer 缓冲区中,保留多大的空间,用于数据的接收。 如这个参数设为0,那么在连接的接受过程中,不会再一道接收任何数据。 
   
  dwLocalAddressLength 和 dwRemoteAddressLength 参数也是以字节为单位,指定在 lpOutputBuffer 缓冲区中,保留多大的空间, 在一个套接字被接受的时候,用于本地和远程地址信息的保存。 要注意的是,和当前采用的传送协议允许的最大地址长度比较起来,这里指定的缓冲区大小至少应多出16字节。 举个例子来说:假定正在使用的是 TCP/IP 协议,那么这里的大小应设为“SOCKADDRIN 结构的长度+16字节”。 
   
  lpdwBytesReceived 参数用于返回接收到的实际数据量,以字节为单位。 只有在操作以同步方式完成的前提下,才会设置这个参数。假如 AcceptEx 函数返回 ERROR_IO_PENDING, 那么这个参数永远都不会设置,我们必须利用完成事件通知机制,获知实际读取的字节量。 
   
  lpOverlapped 参数对应的是一个 OVERLAPPED 结构,允许 AcceptEx 以一种异步方式工作。 如我们早先所述,只有在一个重叠 I/O 应用中,该函数才需要使用事件对象通知机制,这是由于此时没有一个完成例程参数可供使用。 也就是说 AcceptEx 函数只能由 “事件通知”方式获取异步 I/O 请求的结果,而“完成例程”方法无法被使用。

这篇关于重叠I/O(Overlapped I/O)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/228427

相关文章

【代码随想录|贪心part04以后——重叠区间】

代代码随想录|贪心part04以后——重叠区间 一、part041、452.用最少数量的箭引爆气球2、435. 无重叠区间2、763.划分字母区间3、56. 合并区间4、738.单调递增的数字 总结 python 一、part04 1、452.用最少数量的箭引爆气球 452. 用最少数量的箭引爆气球 class Solution:def findMinArrowShot

SQL进阶技巧:每年在校人数统计 | 区间重叠问题

目录 0 问题分析 1 数据准备 2 问题分析 3 小结 区间重叠问题 0 问题分析  有一个录取学生人数表 in_school_stu,记录的是每年录取学生的人数及录取学生的学制,计算每年在校学生人数。 1 数据准备 create table in_school_stu as(select stack(5,1,2001,2,1200,2,2000,5,1300,

WSA重叠IO

服务端: #include <iostream>#include <WinSock2.h>#pragma comment(lib,"ws2_32.lib")#include <Windows.h>#define PORT 6000#define IP_ADDRESS "127.0.0.1"#define MSGSIZE 1024class PerSocketData{pub

【3.8】贪心算法-解无重叠区间

一、题目         给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。 示例 1: 输入: intervals = [[1,2],[2,3],[3,4],[1,3]]输出: 1解释: 移除 [1,3] 后,剩下的区间没有重叠。 示例 2: 输入: intervals

算法训练第26天|452. 用最少数量的箭引爆气球|435. 无重叠区间|763.划分字母区间

LeetCode 452. 用最少数量的箭引爆气球 题目链接:452. 用最少数量的箭引爆气球 题目讲解:代码随想录 func findMinArrowShots(points [][]int) int {var res int = 1// 先按照第一位排序sort.Slice(points, func(i, j int)bool{return points[i][0] < points

《python语言程序设计》2018版第8章第5题特定字符的出现次数 使用下面的函数头,统计一个特定的不重叠的字符串在另一个字符串中出现的次数

我感觉我答的不对,应该和题有点偏差 def count(text_input1, text_input2, ch):a = str(text_input1)b = str(text_input2)count_num_1 = 0count_num_2 = 0if ch in a and ch in b:if ch in a:count_num_1 += 1if ch in b:count_nu

贪心算法---无重叠区间

题目:给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。 思路:将intervals数组按照左边界从小到大进行排序,用count记录无交叉的区间数量。遍历数组,如果正在遍历的区间与上一个区间有重叠,则将该区间的右边界更新为两个区间的最小右边界。如果正在遍历的区间与上一个区间无重叠,则c

nuxt3打包发布以后出现页面重叠

最近用到了nuxt3去写网站,开发过程很顺利,问题出在打包以后发布服务器,有的页面点了会出现多个页面在一个里面,页面重叠了,头部和底部这部分的公共区域还是一个,只有插入的页面有多个。 注意:检查你的页面是不是完全的静态页面,没有用到js,我的页面多个就是因为是纯静态没有用到js导致这个问题,找了很多网上的方案都没有用,什么修改路由配置啊,最后结果是因为没有用js,最后我用了一个for循环去循环了

leetcode435:无重叠区间

无重叠区间 给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。 public int eraseOverlapIntervals(int[][] intervals) {Arrays.sort(intervals,(o1,o2) -> {return o1[0] - o2[0];}

代码随想录算法训练营day30 | 贪心算法 | 452.用最少数量的箭引爆气球、435.无重叠区间、763.划分字母区间

文章目录 452.用最少数量的箭引爆气球思路 435.无重叠区间思路 763.划分字母区间思路问题的转化 总结 今天是贪心算法专题的第四天,今天的三道题目,都算是 重叠区间 问题,大家可以好好感受一下。 都属于那种看起来好复杂, 但一看贪心解法,惊呼:这么巧妙! 这种题还是属于那种,做过了也就会了,没做过就很难想出来 不过大家把如下三题做了之后, 重叠区间 基本上差不多