重叠I/O(Overlapped I/O)模型的学习
- 参考与学习:
- 重叠结构(OVERLAPPED), Windows中所有的异步通信都是基于它的. 至于为什么叫Overlapped?Jeffrey Richter的解释是因为“执行I/O请求的时间与线程执行其他任务的时间是重叠(overlapped)的”
- 优势:
- 可以运行在支持Winsock2的所有Windows平台(而不像完成端口只是支持NT系统)。
- 比起阻塞、select轮询、WSAAsyncSelect以及WSAEventSelect等模型,重叠I/O(Overlapped I/O)模型使应用程序能达到更佳的系统性能。
- 前面那些模型是数据到达并拷贝到套接字的缓冲区中,再通知应用程序到位了来拿吧,应用程序再把缓冲区的数据取走;Overlapped I/O模型下则是应用程序直接投递一个缓冲区,当数据到达套接字后将直接被拷贝到投递的缓冲区。
- 前面那些模型是数据到达并拷贝到套接字的缓冲区中,再通知应用程序到位了来拿吧,应用程序再把缓冲区的数据取走;Overlapped I/O模型下则是应用程序直接投递一个缓冲区,当数据到达套接字后将直接被拷贝到投递的缓冲区。
- 《windows网络编程》中提供的试验结果证明了该模式的高性能。
- 可以运行在支持Winsock2的所有Windows平台(而不像完成端口只是支持NT系统)。
- 基本原理
- 重叠模型是让应用程序使用重叠数据结构(WSAOVERLAPPED),一次投递一个或多个Winsock I/O请求。针对这些提交的请求,在它们完成之后,应用程序会收到通知,就可以通过自己另外的代码来处理这些数据。
- 重叠模型是让应用程序使用重叠数据结构(WSAOVERLAPPED),一次投递一个或多个Winsock I/O请求。针对这些提交的请求,在它们完成之后,应用程序会收到通知,就可以通过自己另外的代码来处理这些数据。
- PS:使用Overlapped I/O,将会使用WSASend、WSARecv,WSASendto、WSARecvFrom代替原先的Send、Recv...进行传输。这些WSA~系列的函数都包含一个Overlapped参数。
- 有两个方法可用来管理重叠IO请求的完成情况(即接到重叠操作完成的通知):
- 事件对象通知(event object notification)
- 完成例程(completion routines)
- 事件对象通知(event object notification)
- 事件通知实现Overlapped I/O
- 基于事件通知,就要将Windows事件对象与WSAOVERLAPPED结构关联。由WSAOVERLAPPED结构可见:
- WSAOVERLAPPED结构
- 五参hEvent即用来绑定WSAEvent对象
- 使用Overlapped I/O,将会使用WSASend、WSARecv,WSASendto、WSARecvFrom代替原先的Send、Recv...进行传输。这些WSA~系列的函数都包含一个Overlapped参数,可以理解为:通过Overlapped参数我们可以在使用WSASend\WSARecv\...等操作发出请求时将其投递到一个重叠模型上,而重叠模型又会与一个事件对象绑定,那此时我们在发出请求后就可以忙后面的事,等重叠操作完成后,绑定的对应的事件就会来通知我们操作完成。
- WSARecv
- 返回WSA_IO_PENDING说明操作成功,但I/O操作还没完成(因此需要绑定一个事件来通知我们何时完成)
- 用例:
- 其他仨函数大差不差,我理解都是借助重叠模型绑定事件,之后发起异步请求,在忙后面事的同时,等待重叠操作那边的事件通知。下面就看看等待事件触发的函数
- 返回WSA_IO_PENDING说明操作成功,但I/O操作还没完成(因此需要绑定一个事件来通知我们何时完成)
- WSAWaitForMultipleEvents --- WSA~系列的等待事件触发
- WSAWaitForMultipleEvents 参数
- 返回WSA_WAIT_TIMEOUT就说明事件还在跑,正常现象,需要做的就是继续wait。
- 返回WSA_WAIT_FAILED说明出现错误,应检查cEvents和lphEvents。
- 如果fWaitAll设置为FALSE,事件数组中有某一个事件被传信了,函数会返回这个事件的索引值,但是这个索引值需要减去预定义值 WSA_WAIT_EVENT_0才是这个事件在事件数组中的位置。
- 返回WSA_WAIT_TIMEOUT就说明事件还在跑,正常现象,需要做的就是继续wait。
- Ps:WSAWaitForMultipleEvents函数只能支持由WSA_MAXIMUM_WAIT_EVENTS对象定义的一个最大值(64),即说明单个WSAWaitForMultipleEvents最多只能等待64个事件,如果想同时等待多于64个事件,就得创建额外的工作者线程,就不得不去管理一个线程池。
- WSAWaitForMultipleEvents 参数
- WSAGetOverlappedResult --- 查询重叠操作的结果
- 参数
- 唯一需要注意一下的就是如果WSAGetOverlappedResult完成以后,第三个参数返回是 0 ,则说明通信对方已经关闭连接,我们这边的SOCKET, Event之类的也就可以关闭了。
- 唯一需要注意一下的就是如果WSAGetOverlappedResult完成以后,第三个参数返回是 0 ,则说明通信对方已经关闭连接,我们这边的SOCKET, Event之类的也就可以关闭了。
- 参数
- 使用也相对简单,并非像我先前理解的必须要使用acceptEx,acceptEx可能更服务于完成端口吧,而且也不是必须的。基于事件通知的重叠操作,在accpet拿到客户端socket后,即可绑定到重叠模型,再将重叠模型绑定到事件对象,此时就得开两个线程,一个线程负责进行WSASend、WSARecv...,一个线程负责WSAWaitForMultipleEvents和等待到事件后WSAGetOverlappedResult 。当然也可以放到一个线程去用,但是搞这玩意儿不就是为了多线程异步操作么?
- 要注意的是,一个socket的操作,对应一个WSAOVERLAPPED结构,对应一个WSAEVENT事件。对,是操作,如果一个socket同时进行了两个操作,同时只有一个操作,比如WSARecv,那么一个socket就可以对应一个WSAOVERLAPPED结构,但是如果一个socket上会有 WSARecv 和 WSASend 两个操作,那么一个SOCKET肯定就要对应两个WSAOVERLAPPED结构。所以有多少个SOCKET操作就会有多少个WSAOVERLAPPED结构,有多少个WSAOVERLAPPED结构就应该有多少个WSAEVENT事件。
- 要注意的是,一个socket的操作,对应一个WSAOVERLAPPED结构,对应一个WSAEVENT事件。对,是操作,如果一个socket同时进行了两个操作,同时只有一个操作,比如WSARecv,那么一个socket就可以对应一个WSAOVERLAPPED结构,但是如果一个socket上会有 WSARecv 和 WSASend 两个操作,那么一个SOCKET肯定就要对应两个WSAOVERLAPPED结构。所以有多少个SOCKET操作就会有多少个WSAOVERLAPPED结构,有多少个WSAOVERLAPPED结构就应该有多少个WSAEVENT事件。
- 基于事件通知,就要将Windows事件对象与WSAOVERLAPPED结构关联。由WSAOVERLAPPED结构可见:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具