• Windows的异步通知I/O模型


    Windows的异步通知I/O模型

    2019526

    10:51

       

    同步和异步直接百度一下应该还算很容易理解吧,虽然我一开始看这个同步和异步的时候也是疑惑了一下,觉得名字起的好奇怪啊。但是现在来看的话,名字起的还是意外的形象呢?有点迷。

       

    • 同步方法调用一旦开始,调用者必须等到方法调用返回后,才能继续后续的行为。
    • 异步方法调用更像一个消息传递,一旦开始,方法调用就会立即返回,调用者就可以继续后续的操作。而,异步方法通常会在另外一个线程中,"真实"地执行着。整个过程,不会阻碍调用者的工作。

       

    来自 <https://www.cnblogs.com/anny0404/p/5691379.html>

       

    要是让我来打一个比方的话,就是比如有一条cpu的时间线(单核cpu的时间线当然是只有一条的),然后其他的进程或者线程就是一条一条的虚线。他们再一起可以重合成为cpu的时间线,当然他们自己本身是断断续续的。然而我们如果将他们缩放看来的话,会不会发现虚线之间空白的部分会越来越小,直至消失不见。这就好像多出了几个和cpu的时间线完全平行的时间线了。(对于单核cpu)

       

    例如我们一开始的read(recv),write(send)都是同步方式的IO函数。select也是同步函数。

       

    理解和实现异步通知I/O模型

    异步通知I/O模型的实现方法有2种:WSAEventSelect函数,WSAAsyncSelect函数

    其中WSAAsyncSelect函数需要指定Windows句柄以获取发生的事件(UI相关内容)

       

    告知I/O状态变化的操作就是"通知"。I/O的状态变化可以分为不同的情况:

    • 套接字的状态变化:套接字的I/O状态变化
    • 发生套接字相关事件:发生套接字IO相关事件

       

    指定某一套接字为事件监视对象:

    #include <winsock2.h>

    int WSAEventSelect(SOCKET s, WSAEVENT hEventObject,

    long lNetworkEvents);

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

       

    s:套接字句柄

    hEventObject: 事件对象句柄

    lNetworkEvents:希望监视的事件类型信息

       

    该函数以异步方式工作。只要s套接字种发生了lNetworkEvents种所指定的事件之一。WSAEventsSelect的异步线程就将hEventObject句柄所指向的内核对象更改为signaled状态。所以这个函数也称为"连接事件对象和套接字的函数"。

       

    第三个参数的事件类型信息,可以通过位或方式同时指定多个信息:

    • FD_READ:是否存在需要读取的数据
    • FD_WRITE:能否以非阻塞方式传输数据
    • FD_OOB:是否收到带外数据
    • FD_ACCEPT:是否有新的连接请求
    • FD_CLOSE:是否有断开连接的请求

       

    WSAEventSelect函数每次只能传递一个套接字的监视信息。但是于select函数相比的是,通过WSAEventSelect函数传递的套接字信息以注册到操作系统,所以无需再次调用。

       

    manual-reset模式事件对象的其他创建方法

    使用WSACreateEvent函数直接创建manual-reset模式non-signaled状态的事件对象

    #include <winsock2.h>

    WSAEVENT WSACreateEvent(void);

    ->>成功是返回事件对象句柄,失败时返回WSA_INVALID_EVENT

       

    WSAEVENT的定义如下:

    #define WSAEVENT HANDLE

       

    销毁WSACreateEvent函数创建的事件对象

    #include <winsock2.h>

    BOOL WSACloseEvent(WSAEVENT hEvent);

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

       

    虽然直接使用CloseHandle也可以

       

    验证是否发生事件

    虽然使用WaitForMultipleEvents也是可以验证socket是否发生事件

    #include <winsock2.h>

    DWORD WSAWaitForMultipleEvents(DWORD cEvents,

    const WSAEVENT * lphEvents);

    ->>成功时返回发生事件的对象组的最小索引,失败返回WSA_INVALID_EVENT,等待超时返回WSA_WAIT_TIMEOUT

       

    cEvents:需要验证的事件对象的个数

    lphEvents:事件对象句柄数组地址

    fWaitAll:是否等待全部,TRUE是,FALSE否

    dwTimeout:指定超时事件,以毫秒为单位。WSA_INFINITE阻塞

    fAlertable:传递TRUE进入alertable_wait(可警告等待状态)

    返回值:返回值减去WSA_WAIT_EVENT_0为发生事件的对象组的最小索引(如果有多个的话)

       

    WSA_MAXIMUM_WAIT_EVENTS指定了WSAWaitForMultipleEvents函数同时可以监视的最大事件对象数。为64

       

    posInfo = WSAWaitForMultipleEvents(numOfSock, hEventArray, FALSE, WSA_INFINITE, FALSE);

    startIdx = posInfo - WSA_WAIT_EVENT_0;

    for(I = startIdx; I < numOfSock; i++)

    {

    int sigEventIdx = WSAWaitForMultipleEvents(1, &hEventArray[i], TRUE, 0, FALSE);

    }

       

    区分事件类型

    #include <winsock2.h>

    int WSAEnumNetworkEvents(SOCKET s, WSAEVENT hEventObject,

    LPWSANETWORKEVENTS lpNetworkEvents);

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

       

    lpNetworkEvents:保存发生的事件类型信息和错误信息的WSANETWORKEVENTS结构体变量地址值

    调用该函数以后才会将manual-reset模式的事件对象更改为non-signaled状态,所以之后不必再单独调用ResetEvent函数。

       

    typedef struct _WSANETWORKEVENTS

    {

    long lNetworkEvents;

    int iErrorCode[FD_MAX_EVENTS];

    }WSANETWORKEVENTS, * LPWSANETWORKEVENTS;

    lNetworkEvents保存发生的事件信息,使用位与&运算验证

    iErrorCode数组种保存了对应事件的错误信息,使用iErrorCode[FD_XXX_BIT]查看对应事件的错误信息

       

    WSANETWORKEVENTS netEvents;

    WSAEnumNetworkEvents(hSock, hEvent, &netEvents);

    if(netEvents.lNetworkEvents & FD_ACCEPT)

    {

    // FD_ACCEPT 事件处理

    }

    if(netEvents.lNetworkEvents & FD_READ)

    {

    // FD_READ 事件处理

    }

    if(netEvents.lNetworkEvents & FD_CLOSE)

    {

    // FD_CLOSE 事件处理

    }

       

    同时如果对应事件发生错误,那么iErrorCode[FD_XXX_BIT]中应存储0以外的值

    WSANETWORKEVENTS netEvents;

    WSAEnumNetworkEvents(hSock, hEvent, &netEvents);

    if(netEvents.iErrorCode[FD_READ_BIT] != 0)

    {

    // 发生FD_READ事件相关错误

    }

  • 相关阅读:
    关于JSON可能出现的错误,待更/todo
    mongoose的安装与使用(书签记录) 2017
    HTTP的学习记录3--HTTPS和HTTP
    HTTP的学习记录(二)头部
    HTTP(一)概述
    LeetCode 455. Assign Cookies
    LeetCode 453. Minimum Moves to Equal Array Elements
    LeetCode 448. Find All Numbers Disappeared in an Array
    LeetCode 447. Number of Boomerangs
    LeetCode 416. Partition Equal Subset Sum
  • 原文地址:https://www.cnblogs.com/freesfu/p/10925690.html
Copyright © 2020-2023  润新知