WSAEventSelect模型是另外一个异步I/O模型,它与WSAAsyncSelect的最大区别是网络事件发生时系统通知应用程序的方式不同,WSAAsyncSelect以消息形式通知应用程序,而WSAEventSelect以事件形式进行通知。

1、WSAEventSelect()函数
WSAEventSelect函数可以为Socket注册网络事件,并将指定的事件关联到指定的网络事件集合。

int WSAEventSelect(Socket s,WSAEVENT hEventObject,long lNetworkEvents);

s:Socket;
hEventObject:与网络事件集合相关联的事件句柄;
lNetworkEvents:感兴趣的网络事件集合;
WSAEventSelect函数设置相关的事件对象,并在网络事件内部记录中保存时间的发生。
应用程序调用WSAWaitForMultipleEvens函数等待事件的发生,调用WSAEnumNetwordEvents函数获取内部网络事件记录的内容,决定发生了哪个被提名的网络事件。

2、WSAWaitForMultipleEvens()函数
在调用WSAEventSelect函数注册网络事件后,应用程序需要等待网络事件的发生,然后对网络事件进行处理。调用后,WSAWaitForMultipleEvens()函数处于阻塞状态,直到出现下面两种情况之一才返回。
(1)指定的一个或多个事件对象处于已授信状态,即发生了指定的网络事件;
(2)阻塞事件超过超时时间。

DWORD WSAWaitForMultipleEvents(
DWORD cEvents,                         // 等候事件的总数量
const WSAEVENT* lphEvents,             // 事件数组的指针
BOOL fWaitAll, 
// 如果设置为 TRUE,则事件数组中所有事件被传信的时候函数才会返回
// FALSE则任何一个事件被传信函数都要返回

DWORD dwTimeout,    
/*超时时间,如果超时,函数会返回 WSA_WAIT_TIMEOUT
如果设置为0,函数会立即返回
如果设置为 WSA_INFINITE只有在某一个事件被传信后才会返回,则  WSAWaitForMultipleEvents 永远等待,不会出现超时现象。*/

BOOL fAlertable
/*该值指定线程是否为alertable等待状态,此时系统能执行一些I/O 完成例程。如果值为真,当系统执行I/O完成例程时线程被处于altertable 等待状态且WSAWaitForMultipleEvents 返回。在这种情况下,返回WSA_WAIT_IO_COMPLETION ,并且等待的event 不会触发信号状态。程序必须重新调用WSAWaitForMultipleEvents 函数。如果为false,线程不处于altertable 等待状态,并且I/O 完成例程不会执行。  
);

3、WSAEnumNetwordEvents()函数

int WSAEnumNetwordEvents(SOCKET s,WSAEVENT hEventObject,LPWSAWSANetwordEvents)

typedef struct _WSANETWORKEVENT{
    long lNetworkEvents;
    int iErrorCode[FD_MAX_EVENTS];
}

lNetworkEvents:指定发生的网络事件;
iErrorCode:错误码数组。

4、基于WSAEventSelect模型的服务器
(1)Init

WSAEVENT eventArray[WSA_MAXIMUM_WAIT_EVENTS];
SOCKET sockArray[WSA_MAXIMUM_WAIT_EVENTS];
int nEventTotal=0;
USHORT port=9000;
sockaddr_in saddr;

InitSock initsock;
saddr.sin_family=AF_INET;
saddr.sin_port=htons(port);
saddr.sin_addr.s_addr=htonl(ADDR_ANY);
SOCKET server=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
bind(server,(sockaddr*)&saddr,sizeof(saddr));
listen(server,5);

// 创建时间,并把监听Socket关联
WSAEVENT myevent=WSACreateEvent();
WSAEventSelect(server,myevent,FD_ACCEPT|FD_CLOSE);
// 监听事件、Socket添加的到句柄表中
eventArray[nEventTotal]=myevent;
sockArray[nEventTotal]=server;
++nEventTotal;

(2)等待事件发生

int nIndex=WSAWaitForMultipleEvents(nEventTotal,eventArray,FALSE,WSA_INFINITE,FALSE);
// 只要发生一个事件就返回
nIndex=nIndex-WSA_WAIT_EVENT_0;
// 返回值减去WSA_WAIT_EVENT_0表示lphEvents满足等待的对象的数组索引

(3)检测发生事件

for(int i=nIndex;i<nEventTotal;++i)
        {
            int ret;
            ret=WSAWaitForMultipleEvents(1,&eventArray[i],TRUE,1000,FALSE);
            if(ret==WSA_WAIT_FAILED || ret==WSA_WAIT_TIMEOUT)
            {
                cout<<"超时"<<endl;
                continue;
            }
            else
            {
                // 查看具体事件(READ\WRITE\ACCEPT)
                WSANETWORKEVENTS event1;
                WSAEnumNetworkEvents(sockArray[i],eventArray[i],&event1);
                if(event1.lNetworkEvents & FD_ACCEPT)
                {
                    // no error
                    if(event1.iErrorCode[FD_ACCEPT_BIT]==0)
                    {
                        if(nEventTotal>WSA_MAXIMUM_WAIT_EVENTS)
                        {
                            cout<<"连接数太多"<<endl;
                            continue;
                        }

                        SOCKET client=accept(sockArray[i],NULL,NULL);
                        WSAEVENT newEvent=WSACreateEvent();
                        WSAEventSelect(client,newEvent,FD_READ|FD_WRITE|FD_CLOSE);
                        eventArray[nEventTotal]=newEvent;
                        sockArray[nEventTotal]=client;
                        ++nEventTotal;
                    }
                    else
                        cout<<"FD_ACCEPT error"<<endl;
                }
                else if(event1.lNetworkEvents & FD_READ)
                {
                    // 接收消息
                    if(event1.iErrorCode[FD_READ_BIT]==0)
                    {
                        char buf[64];
                        ZeroMemory(buf,64);
                        int nRecv=recv(sockArray[i],buf,64,0);
                        if(nRecv>0)
                        {
                            buf[nRecv]='\0';
                            cout<<buf<<endl;

                            // 发送消息
                            strcpy(buf,"msg received!");
                            send(sockArray[i],buf,sizeof(buf),0);
                        }
                        else
                            cout<<"no msg"<<endl;
                    }
                    else
                        cout<<"FD_READ error"<<endl;
                }
                else if(event1.lNetworkEvents & FD_CLOSE)
                {
                    if(event1.iErrorCode[FD_CLOSE_BIT]==0)
                    {
                        closesocket(sockArray[i]);
                        for(int j=i;j<nEventTotal-1;++j)
                        {
                            sockArray[j]=sockArray[j+1];
                            eventArray[j]=eventArray[j+1];
                        }
                        --nEventTotal;
                    }
                    else
                        cout<<"FD_CLOSE error"<<endl;
                }
            }
        }

标签: none

评论已关闭