频道栏目
首页 > 资讯 > 其他综合 > 正文

网络编程—— Windows下的异步通知IO

17-01-04        来源:[db:作者]  
收藏   我要投稿

网络编程—— Windows下的异步通知IO

一、同步IO和异步IO

同步IO是指发生IO事件的时间点和相关函数返回的时间点一致。如使用send函数发送数据时,所有的数据发送到输出缓冲区后,send函数才会返回,这种IO方式就是同步IO。异步IO指函数先于IO事件返回。还是以send函数为例,调用send函数后其马上返回,而数据传送到输出缓冲区交给操作系统完成。这种IO方式就是同步IO。

什么是异步IO通知?

异步IO通知是指每当发生了IO事件——有数据需要写或读,操作系统就会产生一个事件,而我们可以根据这个事件进行相应的处理。

二、使用WSAEventSelect函数监视套接字

WSAEventSelect函数可以监视一个套接字,当套接字发生IO事件后,它会产生一个异步事件,并将该事件传到WSAEventSelect函数的参数中。WSAEventSelect的函数原型如下:

 

int WSAEventSelect(
  __in SOCKET s,
  __in WSAEVENT hEventObject,
  __in long lNetworkEvents
);

 

s —— 需要监视的socket文件描述符。

hEventObject —— 异步事件句柄。当发生lNetworkEvents所指定的的事件时,WSAEventSelect会将该句柄所指的内核对象改为signaled状态。

lNetworkEvents —— 注册的需要监视的事件,按位表示。支持的事件列表如下:

事件宏

描述

FD_READ

是否存在需要读取的数据

FD_WRITE

是否有需要传递的数据

FD_ACCEPT

是否有新的连接请求

FD_CLOSE

是否有需要断开的连接

三、使用WSACreateEvent创建non-signaled事件

现在,我们需要创建一个man-reset的non-signaled事件,来传递给WSAEventSelect的第二个参数。我们可以选择使用CreateEvent函数,它可以选择创建的事件是man-reset还是auto-reset、signaled还是non-signaled。但是使用WSACreateEvent函数会更加方便,因为它直接就可以创建一个man-reset的non-signaled事件,而无需任何参数。WSACreateEvent的函数原型如下:


HANDLE WSACreateEvent(void);
如果需要关闭事件,则调用WSACloseEvent函数:

BOOL WSACloseEvent( __in WSAEVENT hEvent );

四、使用WSAWaitForMultipleEvents验证是否发生事件

WSAWaitForMultipleEvents用来验证是否发生了相关的异步事件,其原型如下:


DWORD WSAWaitForMultipleEvents( __in DWORD cEvents, __in const WSAEVENT *lphEvents, __in BOOL fWaitAll, __in DWORD dwTimeout, __in BOOL fAlertable );
cEvents —— 需要验证是否转变为signaled事件的总的个数。
lphEvents —— 存放事件句柄的数组。
fWaitAll —— 置为True时,所有事件变成Signaled状态时返回;置为False时,只要发生一个事件变成signaled状态就返回。
dwTimeout —— 设置等待超时,如果设为WSA_INFINITE则一直等待,直到事件变为signaled状态。
fAlertable —— 传递为True时进入alertable wait状态。
返回值 —— 返回值减去WSA_WAIT_EVENT_0时,得到是发生变成signaled状态的事件在lphEvents的索引值(是索引最小的那个事件的索引值)。

五、使用WSAEnumNetworkEvents区分事件类型

当我们通过使用WSAWaitForMultipleEvents等待到一个事件所指的内核对象变成singnaled状态之后,我们可以使用WSAEnumNetworkEvents来验证该事件的类型,是FD_READ事件、FD_WRITE事件还是FD_ACCEPT事件?

WSAEnumNetworkEvents的原型如下:


int WSAEnumNetworkEvents( __in SOCKET s, __in WSAEVENT hEventObject, __out LPWSANETWORKEVENTS lpNetworkEvents );

s —— 是监视的socket描述符。

hEventObject—— 是创建的异步通知IO事件。

lpNetworkEvents —— 是WSANETWORKEVENTS结构体对象,该结构体的定义如下:

typedef struct _WSANETWORKEVENTS { long lNetworkEvents; int iErrorCode[FD_MAX_EVENTS]; } WSANETWORKEVENTS, *LPWSANETWORKEVENTS;
    WSANETWORKEVENTS里的lNetworkEvents用来保存发生的事件类型,我们可以通过位与操作判断是否是发生了某事件:

 

If((netEvents.lNetworkEvents &FD_ACCEPT)
{
    ……
}

 

    iErrorCode保存的是发生的错误码的位数组,通过数组成员判断发生的错误类型:

 

if(netEvents.iErrorCode[FD_CLOSE_BIT]!=0)
{
    puts("close error");
}

 

六、代码示例

以下代码,是使用异步IO通知事件实现的服务端代码:

 

// WSAEventSelectServ.cpp : 定?§义°?控?制?台??§应®|用®?程¨?序¨°的ì?入¨?口¨2点ì?。?ê
//
 
#include "stdafx.h"
#include
#include
#include
 
#pragma comment(lib,"ws2_32.lib")
 
#define BUF_SIZE 30
#define EVENT_SIZE 64
 
void ErrorHandler(const char* message);
void CompressEvents(HANDLE* events,int pos,int size);
void CompressSocks(SOCKET* socks,int pos,int size);
 
int _tmain(int argc, _TCHAR* argv[])
{
    WSADATAwsaData;
 
    SOCKETservSock,clntSock;
    SOCKADDR_INservAddr,clntAddr;
    int clntAddrSz;
    SOCKETsocks[EVENT_SIZE];
    int strLen;
    int eventNum = 0;
 
    char buf[BUF_SIZE];
 
    HANDLEhEvent;
    HANDLEevents[EVENT_SIZE];
    int minPos;
    WSANETWORKEVENTSnetEvents;
   
 
    if(WSAStartup(MAKEWORD(2,2),&wsaData)==SOCKET_ERROR)
        ErrorHandler("WSAStartUp Error");
 
    servSock=socket(AF_INET,SOCK_STREAM,0);
    if(servSock==INVALID_SOCKET)
        ErrorHandler("socket error");
 
    memset(&servAddr,0,sizeof(servAddr));
    servAddr.sin_family=AF_INET;
    servAddr.sin_addr.s_addr=INADDR_ANY;
    servAddr.sin_port=htons(atoi("8888"));
 
    if(bind(servSock,(constsockaddr*)&servAddr,sizeof(servAddr))==SOCKET_ERROR)
        ErrorHandler("bind error");
 
    if(listen(servSock,5)==SOCKET_ERROR)
        ErrorHandler("listen error");
 
    hEvent=WSACreateEvent();
    //将?用®?来¤??监¨¤视o¨®servSock的ì?事o?件t放¤?到ì?第ì¨2一°?个?位?置?
    events[eventNum]=hEvent;
    socks[eventNum]=servSock;
 
    //注á?é册¨¢servSock
    WSAEventSelect(servSock,hEvent,FD_ACCEPT);
 
    while(1)
    {
        //调ì??用®?WSAWaitForMultipleEvents等쨨待?y事o?件t变à?成¨|signaled状á??态??,ê?设|¨¨置?等쨨待?y一°?个?事o?件t即??返¤|ì回?
        //且¨°不?设|¨¨置?超?时o?à,ê?永®¨¤远?等쨨待?y
        minPos=WSAWaitForMultipleEvents(eventNum+ 1,events,false,WSA_INFINITE,false);
        //得ì?到ì?索??引°y值|ì
        minPos=minPos-WSA_WAIT_EVENT_0;
        //遍à¨|历¤¨2数oy组á¨|其?他?元a素?,ê?调ì??用®?WSAWaitForMultipleEvents,ê?验¨|证?è其?他?元a素?对?应®|的ì?内¨2核?对?象¨®是o?否¤?进?入¨?
        //signaled状á??态??
        for (inti=minPos;i

Github位置: https://github.com/HymanLiuTS/NetDevelopment

克隆本项目: gitclonegit@github.com:HymanLiuTS/NetDevelopment.git

获取本文源代码: gitcheckout NL52

 

 

 

相关TAG标签
上一篇:牛哥:网络小白被“革杀”,为何只差一毫米的距离!
下一篇:Intel至强E5-2620v4处理器 详细参数介绍
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站