zoukankan      html  css  js  c++  java
  • windows的重叠IO模型

    windows的重叠IO模型

    2019529

    11:58

       

    同一线程内部向多个目标传输(或冲多个目标接收)数据引起的IO重叠现象称为"重叠IO"。为了完成这项任务,调用IO的函数应立即返回,只有这样才能返送后续数据。

    重叠IO收发数据最重要的前提条件就是异步IO。

    在windows中重叠IO的重点并非IO本身,而是如何确认IO完成时的状态。因为不管输入还是输出,只要时非阻塞模式的,就要另外确认执行结果。确认执行结果前需要经过特殊的处理过程。

       

    创建重叠IO套接字

    #include <winsock2.h>

    SOCKET WSASocket(int af, int type, int protocal, LPWSAPROTOCAL_INFO lpProtocolInfo, GROUP g, DWORD dwFlags);

    ->>成功时返回套接字句柄,失败时返回INVALID_SOCKET

       

    af 协议族信息

    type 套接字数据传输方式

    protocol 套接字使用协议信息

    lpProtocalInfo 包含创建的套接字信息的WSAPROTOCAL_INFO结构体变量地址值,不需要时传递NULL

    g 为扩展函数二预约的参数,可以使用0

    dwFlags 套接字属性信息

       

    首先是创建重叠IO套接字,并且之后要使用特殊的重叠IO函数收发数据,并且在收发数据以后通过特殊方法确认收发数据的成功与否。如果需要还可以通过注册在IO完成以后执行指定的函数。

       

    执行重叠IOWSASend函数

    #include <winsock2.h>

    int WSASend(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,

    LPDWORD lpNumberOfBytesSent, DWORD dwFlags,

    LPWSAOVERLAPPED lpOverlapped,

    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);

    ->>成功时返回0,失败时返回SOCKET_ERROR

       

    s 套接字句柄,传递具有重叠IO属性的套接字句柄时,以重叠IO模型输出

    lpBuffers WSABUF结构体变量数组的地址值,WSABUF中存有待传输的数据

    dwBufferCount 第二个参数中数组的长度

    lpNumberOfBytesSent 用于保存实际发送字节数的变量地址

    dwFlags 用于更改数据传输特性

    lpOverlapped WSAOVERLAPPED结构体变量的地址值,使用事件对象,用于确认完成数据传输

    lpCompletionRoutine 传入Completion Routine函数的入口地址值,可以通过干函数确认是否完成数据传输

       

    WSABUF结构体定义

    typedef struct __WSABUF

    {

    u_long len; // 待传输数据的大小

    char FAR * buf; // 缓冲地址值

    }WSABUF, * LPWSABUF;

       

    示例:

    WSAEVENT event;

    WSAOVERLAPPED overlapped;

    WSABUF databuf;

    char buf[BUF_SIZE] = {"待传输的数据"};

    int recvBytes = 0;

    event = WSACreateEvent();

    memset(&overlapped, 0, sizeof(overlapped)); // 所有位初始化为0

    overlapped.hEvent = event;

    dataBuf.len = sizeof(buf);

    dataBuf.buf = buf;

    WSASend(hSocket, &dataBuf, 1, &recvBytes, 0, &overlapped, NULL);

       

    WSAOVERLAPPEd 结构体定义如下

    typedef struct _WSAOVERLAPPE

    {

    DWORD Internal;

    DWORD InternalHigh;

    DWORD Offset;

    DWORD OffsetHigh;

    WSAEVENT hEvent;

    }WSAOVERLAPPED, * LPWSAOVERLAPPED;

    Internal, InternalHigh为进行重叠IO时操作系统内部使用的成员,Offset, OffsetHigh同样具有特殊用途,实际只需要关注hEvent成员

       

    如果向overlapped参数传递NUll,则套接字将以阻塞方式工作。同样如果利用WSASend函数向多个目标传输数据,则每个目标都需要具有独自的WSAOVERLAPPED结构体变量

       

    还具有一种情况就是在WSASend调用结束立即返回的同时,数据也同时传输完成。在这个时候WSASend函数返回0,同时在recvBytes中填充发送的字节数。反之(数据没有传输完成),WSASend仍需传输数据时,将返回SOCKET_ERROR,并将WSA_IO_PENDING(尚未完成状态Pending)注册为错误代码(错误代码通过WSAGetLastError获得)。之后通过WSAGetOverlappedResult获取实际传输大小。

       

    执行重叠IOWSARecv函数

    #include <winsock2.h>

    int WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,

    LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags,

    LPWSAOVERLAPPED lpOverlapped,

    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);

    ->>成功时返回0,失败时返回SOCKET_ERROR

       

    s 赋予重叠IO属性的套接字句柄

    lpBuffers 用于保存接收数据的WSABUF结构体数组地址值

    dwBufferCount 向第二个参数传递的数组的长度

    lpNumberOfBytesRecvd 保存接收数据大小信息的地址值

    lpFlags 用于设置或读取传输特性信息

    lpOverlapped WSAOVERLAPPED结构体变量地址

    lpCompletionRoutine Completion Routine函数地址

       

    Gather/Scatter I/O是指将多个缓冲区中的数据积累到一定程度后一次型传输(Gather输出),将接收的数据分批保存(Scatter输入)。Linux下的writev&readv函数具有Gather/Scatter I/O功能,但是windows下并没有这些函数的定义。不过可以通过重叠IO中的WSASend和WSARecv函数获得类似的功能。他们的第二个参数和第三个参数中就可以判断出其具有Gather/Scatter I/O功能。

       

    获得实际传输大小

    #include <winsock2.h>

    BOOL WSAGetOverlappedResult(SOCKET s, LPWSAOVERLAPPED lpOverlapped,

    LPDWORD lpcbTreansfer, BOOL fWait, LPDWORD lpdwFlags);

    ->>成功时返回TRUE,失败时返回FALSE

       

    s 重叠IO套接字

    lpOverlapped WSAOVERLAPPED结构体变量地址

    lpcbTransfer 用于保存实际传输字节数的变量地址

    fWait 如果调用该函数时仍在进行IO,是否等待IO完成,TRUE等待,FALSE不等待(返回FALSE并跳出函数)。

    lpdwFlags 用于获取附加信息(如OOB消息)。如果不需要,可以传递NULL

       

    重叠IOIO完成确认

    重叠IO中有两种方法确认IO的完成并获取结果

    • 利用WSASend、WSARecv函数的第六个参数,基于事件对象
    • 利用WSASend、WSARecv函数的第七个参数,基于Completion Routine

       

    使用前一种方法时需要注意:

    • 完成IO时,WSAOVERLAPPED结构体变量引用的事件对象将编程为signaled状态
    • 为了验证IO的完成和完成结构,需要调用WSAGetOverlappedResult函数

       

    使用Completion Routine函数

    可以通过WSARecv&WSASend函数的最后一个参数中指定的Completion Routine(以下简称CR)函数验证IO完成情况。

       

    "注册CR"有如下含义:"Pending的IO完成以后调用此函数"

    但是如果执行重要任务时突然调用Completion Routine,则有可能会破坏程序的正常执行流。因此操作系统通常都会预先定义规则:"只有请求I/O的线程处于alertalble wait状态时才能调用Completion Routine函数"

       

    "alertable wait状态"时等待接收操作系统消息的线程状态,调用以下函数可以进入alertable wait状态

    • WaitForSingleObjectEx
    • WaitForMultipleObjectsEx
    • WSAWaitForMultipleEvents
    • SleepEx

       

    第一,第二,第四个参数提供的功能与WaitForSingleObject,WaitForMultipleObjects,Sleep函数相同,只是额外增加了1个参数。如果该参数为TRUE,则相应线程进入alertable wait状态

    第三个函数的最后一个参数设置为TRUE时,线程同样进入alertable wait状态。

       

    启动IO任务后,执行完紧急任务时可以调用上述任意函数验证IO完成与否,此时操作系统知道线程进入alertable wait状态,如果有已经完成的IO。则调用相应的Completion Routine函数。调用以后上述函数将全部返回WAIT_IO_COMPLETION,并开始执行接下来的程序

       

    Completion Routine函数原型

    void CALLBACK CompletionROUTINE(DWORD dwError, DWORD cbTransferred,

    LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags);

       

    参数一 中写入错误信息(正常结束时写入0)

    参数二 写入实际收发的字节数

    参数三 写入WSASend,WSARecv函数的参数lpOverlapped

    dwFlags 写入调用IO函数时传入的特性信息或者0

       

       

      

  • 相关阅读:
    uWSGI 是一種協議,同時它也是一個程式。
    影像数据的裁切和保存
    Android Studio、IDEA 获取开发版SHA1值和发布版SHA1值,详细过程
    Android Studio的Signature Versions选择,分别是什么意思
    Android Studio更改项目SDK的版本
    c#+ArcGIS Engine-获取矢量图层的空间参考
    64。node.js 中间件express-session使用详解
    63.note.js之 Mongodb在Nodejs上的配置及session会话机制的实现
    62.nodejs中的ejs模板学习
    61.node.js开发错误——Error: Connection strategy not found
  • 原文地址:https://www.cnblogs.com/freesfu/p/10943508.html
Copyright © 2011-2022 走看看