您的位置:首页 > 其它

WSAEventSelect-事件通知模型

2008-11-12 11:46 531 查看
该模型最主要的差别在于网络事件会投递至一个事件对象句柄,而非投递至一个窗口例程。

事件通知
事件通知模型要求我们的应用程序针对打算使用的每一个套接字,首先创建一个事件对象。创建方法是调用W S A C r e a t e E v e n t函数,它的定义如下:
WSAEVENT WSACreateEvent(void);

WSAWaitForMultipleEvents

若W S AWa i t F o r M u l t i p l e E v e n t s收到一个事件对象的网络事件通知,便会返回一个值,指出造成函数返回的事件对象。这样一来,我们的应用程序便可引用事件数组中已传信的事件,并检索与那个事件对应的套接字,判断到底是在哪个套接字上,发生了什么网络事件类型。对事件数组中的事件进行引用时,应该用 W S AWa i t F o r M u l t i p l e E v e n t s的返回值,减去预定义
值W S A _ WA I T _ E V E N T _ 0,得到具体的引用值(即索引位置)。如下例所示:
Index = WSAWaitForMultipleEvents(...);
MyEvent = EventArray[Index-WSA_WAIT_EVENT_0];
#include <stdio.h>

#include <iostream.h>

#include <windows.h>

// 初始化Winsock库

BOOL InitWinsock()

{

// 初始化Winsock库

}

int main()

{

InitWinsock();

// 事件句柄和套节字句柄表

WSAEVENT eventArray[WSA_MAXIMUM_WAIT_EVENTS];

SOCKET sockArray[WSA_MAXIMUM_WAIT_EVENTS];

int nEventTotal = 0;

USHORT nPort = 4567; // 此服务器监听的端口号

// 创建监听套节字

SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

sockaddr_in sin;

sin.sin_family = AF_INET;

sin.sin_port = htons(nPort);

sin.sin_addr.S_un.S_addr = INADDR_ANY;

if(::bind(sListen, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)

{

printf(" Failed bind() /n");

return -1;

}

::listen(sListen, 5);

// 创建事件对象,并关联到新的套节字

WSAEVENT event = ::WSACreateEvent();

::WSAEventSelect(sListen, event, FD_ACCEPT|FD_CLOSE);

// 添加到表中

eventArray[nEventTotal] = event;

sockArray[nEventTotal] = sListen;

nEventTotal++;

// 处理网络事件

while(TRUE)

{

// 在所有事件对象上等待

int nIndex = ::WSAWaitForMultipleEvents(nEventTotal, eventArray, FALSE, WSA_INFINITE, FALSE);

// 对每个事件调用WSAWaitForMultipleEvents函数,以便确定它的状态

nIndex = nIndex - WSA_WAIT_EVENT_0;

for(int i=nIndex; i<nEventTotal; i++)

{

nIndex = ::WSAWaitForMultipleEvents(1, &eventArray, TRUE, 1000, FALSE);

if(nIndex == WSA_WAIT_FAILED || nIndex == WSA_WAIT_TIMEOUT)

{

continue;

}

else

{

// 获取到来的通知消息,WSAEnumNetworkEvents函数会自动重置受信事件

WSANETWORKEVENTS event;

::WSAEnumNetworkEvents(sockArray, eventArray, &event);

if(event.lNetworkEvents & FD_ACCEPT) // 处理FD_ACCEPT通知消息

{

if(event.iErrorCode[FD_ACCEPT_BIT] == 0)

{

if(nEventTotal > WSA_MAXIMUM_WAIT_EVENTS)

{

printf(" Too many connections! /n");

continue;

}

SOCKET sNew = ::accept(sockArray, NULL, NULL);

WSAEVENT event = ::WSACreateEvent();

::WSAEventSelect(sNew, event, FD_READ|FD_CLOSE|FD_WRITE);

// 添加到表中

eventArray[nEventTotal] = event;

sockArray[nEventTotal] = sNew;

nEventTotal++;

}

}

else if(event.lNetworkEvents & FD_READ) // 处理FD_READ通知消息

{

if(event.iErrorCode[FD_READ_BIT] == 0)

{

char szText[256];

int nRecv = ::recv(sockArray, szText, strlen(szText), 0);

if(nRecv > 0)

{

szText[nRecv] = '/0';

printf("接收到数据:%s /n", szText);

}

}

}

else if(event.lNetworkEvents & FD_CLOSE) // 处理FD_CLOSE通知消息

{

if(event.iErrorCode[FD_CLOSE_BIT] == 0)

{

::closesocket(sockArray);

for(int j=i; j<nEventTotal-1; j++)

{

sockArray[j] = sockArray[j+1];

sockArray[j] = sockArray[j+1];

}

nEventTotal--;

}

}

else if(event.lNetworkEvents & FD_WRITE) // 处理FD_WRITE通知消息

{

}

}

}

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: