• 网络程序设计——重叠I/O模型


    目录

    1、重叠I/O

    (1)概念

    (2)重叠数据结构WSAOVERLAPPED  

    2、重叠I/O的相关函数

    (1)套接字创建

    (2)发送数据函数

    (3)两种获取传输数据数量的方法

    3、 重叠I/O模型的编程框架

    (1)使用事件通知方式进行重叠I/O的编程框架

     (2)使用完成例程方式进行重叠I/O的编程框架

    (3)以面向连接额的数据接收为例

    4、重叠I/O模型评价

    1、重叠I/O

    (1)概念

    •        重叠I/O模型是以Windows重叠I/O机制为基础的套接字I/O模型。Windows重叠I/O本来是一种文件操作技术。在传统文件操作中,文件的读写函数都是以阻塞模式工作的,当文件很大或磁盘读写速度较低时,程序运行就会长时间阻塞在文件的读写操作上,直到读写完成才返回。这样将浪费很多时间,导致程序性能下降。为了解决这个问题,Windows引进了重叠I/O的概念。能同时以多个线程处理多个I/O。
    •       在重叠I/O下,应用程序在调用文件读写函数后函数会立即返回,而不必等待操作结束,文件读写的同时应用程序可以执行其他操作,这就是所谓的异步I/O操作。如果让应用程序连续进行多个文件读写函数的调用,使得系统同时执行多个文件的读写操作,就成为所谓的重叠I/O操作
    •         WinSock的重叠I/O模型就是以重叠I/O机制为基础开发的。从WinSock2开始,重叠I/O模型便被引入到WinSock的扩展套接字函数中,这些扩展函数的格式不再与BSD套接字函数兼容,函数名均以WSA开头,比如recv()函数和send()函数的Windows扩展版分别为WSARecv()和WSASend()。应用程序要使用重叠I/O模型,就必须使用WinSock扩展套接字函数。

    (2)重叠数据结构WSAOVERLAPPED  

    1. typedef struct _WSAOVERLAPPED{
    2. ULONG_PTR Interal; //底层操作系统使用
    3. ULONG_PTR InteralHigh; //底层操作系统使用
    4. union{
    5. struct{
    6. DWORD offset; //套接字是忽略,文件操作使用。
    7. DWORD offsetHigh; //忽略
    8. };
    9. PVOID Pointer; //忽略
    10. };
    11. HANDLE hEvent;//允许应用程序为这个操作关联一个事件对象句柄
    12. }WSAOVERLAPPED, *LPWSAOVERLAPPED;
    •        重叠I/O的事件通知方法需要Windows事件对象关联到WSAOVERLAPPED结构。当I/O完成时,会将WSAOVERLAPPED结构中的hEvents置为有信号状态。
    •       通过调用WSAWaitForMultipleEvents()来等待I/O完成的通知,在得到通知信号后,就可以调用WSAGetOverlappedResult()来查询I/O操作的结果,并进行相关处理。WSAOVERLAPPED结构在重叠I/O请求初始化及其后续的完成之间提供一个沟通或通信机制。

    2、重叠I/O的相关函数

    (1)套接字创建

    1. SOCKET WSASocket{
    2. int af, int type, int protocol,
    3. LPWSAPROTOCOL_INFO lpProtocolInfo,//指定新套接字的特性
    4. GROUP g, //保留
    5. DWORD dwFlags//在重叠I/O模型中,需要设置为WSA_FLAG_OVERLAPPED。
    6. };

    (2)发送数据函数

    1. int WSASend{
    2. SOCKET s,
    3. LPWSABUF lpBuffers,//指向WSABUF结构数组的指针
    4. DWORD dwBufferCount,//记录lpBuffers数组中WSABUF结构的数目
    5. LPDWORD lpNumberOfBytesSent, //返回指向发送的字节数的指针
    6. DWORD dwFlags, //标志
    7. LPWSAOVERLAPPED lpOverlapped, //指向重叠结构的指针
    8. LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
    9. //指向发送操作完成后调用的完成例程
    10. };

           如果重叠操作立即完成,则返回0;如果重叠操作被成功初始化,并且稍后完成,则返回WSA_IO_PENDING。

    (3)两种获取传输数据数量的方法

    • 1)如果指定了完成例程,通过cbTransferred参数获取
    • 2)通过WSAGetOverlappedResult()的参数lpcbTransferred获取。

    3、 重叠I/O模型的编程框架

    WinSock可以使用事件通知和完成例程两种方式来实现重叠I/O的操作。

    (1)使用事件通知方式进行重叠I/O的编程框架

    • 套接字初始化,设置为重叠I/O模式;
    • 创建套接字网络事件对应的用户事件对象;
    • 初始化重叠结构,为套接字管理事件对象;
    • 异步接收数据,无论能否接收到数据,都会直接返回;
    • 调用WSAWaitForMultipleEvents(),在所有事件对象上等待,只要有一个事件对象变为授信状态,则返回;
    • 调用WSAGetOverlappedResult(),获取套接字上的重叠操作状态,并保存到重叠结构中;
    • 根据重置事件的状态进行处理;
    • 重置已授信的事件对象、重叠结构、标志位和缓冲区;
    • 回到步骤4。

     (2)使用完成例程方式进行重叠I/O的编程框架

          对于网络重叠I/O操作,等待I/O操作结束的另一种方法是使用完成例程。异步的发送和接收接口函数的参数中的最后一个参数lpCompletionROUTINE就是用来指向完成例程的指针。若指定此参数,hEvent参数将被忽略,上下文信息将传送给完成例程函数。

    ①完成例程函数原型

    1. void CALLBACK CompletionROUTINE{
    2. DWORD dwError, //指定lpOverlapped参数中表示的重叠操作的完成状态
    3. DWORD cbTransferred, //传送完成的数据数量
    4. LPWSAOVERLAPPED lpOverlapped, //指定重叠结构
    5. DWORD dwFlags //指定操作结束时的标记,通常设置为0
    6. };

    (3)以面向连接额的数据接收为例

    • 套接字初始化,设置为重叠I/O模式;
    • 初始化重叠结构;
    • 异步传输数据,将重叠结构作为输入参数,并指定一个完成例程对应于数据传输后的处理;
    • 调用WSAWaitForMultipleEvents()或SleepEx(),将自己的线程设置为一种可警告等待状态,等待一个重叠I/O请求完成,重叠请求完成后,完成例程会自动执行,在完成例程内,可随一个完成例程一起投递另一个重叠I/O操作;
    • 回到步骤3。

    4、重叠I/O模型评价

    • 应用程序中的I/O操作<-->重叠结构<-->事件
    • 使应用程序能达到更佳的系统性能
    • 减少了一次从I/O缓冲区到应用程序缓冲区的拷贝。

    如有错误,敬请指正。

    您的收藏与点赞都是对我最大的鼓励和支持!

  • 相关阅读:
    docker学习笔记
    【Java集合框架】22 ——SortedMap 接口
    22款奔驰GLE450升级香氛负离子 清新淡雅
    “链上海南”计划发布,能链科技等共建生态联盟
    Java Character.SubSet toString()方法具有什么功能呢?
    前端取图片相同颜色作为遮罩或者背景
    linux 指定时间 执行一次 命令
    知识点2--CMS项目首页
    AOSP编译系统演进:从Make到Ninja的技术升级(Android13)
    开发板TFTP调试
  • 原文地址:https://blog.csdn.net/x20020402/article/details/128062293