Winsock I/O模型--WSAEventSelect模型

WSAEventSelect模型是winsock IO模型中比较常见的一个异步模型,它允许应用程序在一个和多个套接字上,接受以事件为基础的网络事件通知。
步骤一:
        事件通知模型要求我们针对每一个打算使用的套接字,创建一个事件模型。调用下面的函数:
        WSAEVENT WSACreateEvent(void);
        函数的返回值就是一个事件的句柄;
步骤二:
              事件对象句柄创建成功以后,必须将其与某一个套接字关联,同时注册自己感兴趣的网络事件
             int WSAEventSelect( 
                                              IN SOCKET s,             //与之相关联的套接字
                                              IN WSAEVENT hEventObject,//步骤一中的事件句柄 
                                              IN long lNetworkEvents   //感兴趣的网络时间FD_READ。。。
                                             )
             注:该函数创建的事件有两种工作状态:分别是未传信和已传信;工作模式是:人工和自动。
             WSACreateEvent创建是未传信的,关联某一个套接字成为已传信,
              在IO请求处理完之后,我们写的程序需要把已传信状态改为未传信的状态,使用函数是WSAResetEvent;
步骤三:
             套接字与一个事件句柄关联以后,就可以开始IO处理了。方法是等待我们感兴趣的网络事件触发事件句柄的
            工作状态。是的下面的函数:
            DWORD WSAWaitForMultipleEvents
                                                                            (
                                                                                IN DWORD cEvents,                 //事件句柄表的大小
                                                                                IN const WSAEVENT FAR * lphEvents, //事件句柄表的指针
                                                                                IN BOOL fWaitAll,                  //等待全部事件进入已传信状态为TRUE,任何一个设置为FALSE; //通常是FALSE,一次只为一个套接字事件服务
                                                                                IN DWORD dwTimeout,                //超时时间
                                                                                IN BOOL fAlertable                 //忽略为FALSE
                                                                                )
           注意:该函数返回值表示:指向造成函数返回的事件对象。在事件数组上的索引位置是:该返回值减去一个
           预定义WSA_WAIT_EVENT_0;知道了事件索引即可找到对应的套接字。
步骤四:
             知道了套接字就可以查询出发生了什么类型的网络事件。使用下面的函数:
               int WSAEnumNetworkEvents
                                                                 ( 
                                                                      IN SOCKET s,            //造成网络事件的套接字
                                                                      IN WSAEVENT hEventObject,//对应的事件
                                                                      OUT LPWSANETWORKEVENTS lpNetworkEvents //指向WSANETWORKEVENTS结构;
                                                                  )
              typedef struct _WSANETWORKEVENTS 
                      { 
                                long lNetworkEvents; //对应套接字上发生的网络事件,可以是多个
                                 int iErrorCode[FD_MAX_EVENTS];//错误码;
                       } WSANETWORKEVENTS,  *LPWSANETWORKEVENTS;
 最后,对WSANETWORKEVENTS改结构的事件处理完,我们应在所有的可用套接字上继续等待更多的网络事件。
程序实例:
#include "stdafx.h"
#include <stdio.h>
#include <winsock2.h>
#pragma  comment(lib,"ws2_32.lib")

#define  PORT 5150
#define  DATA_BUFSIZE 4096*2

typedef struct SOCKET_INFO 
{
char Buffer[DATA_BUFSIZE];
WSABUF Databuf;
SOCKET socket;
DWORD  bytesRecv;
DWORD  bytesSend;
}SOCKET_INFO,*LPSOCKET_INFO;
DWORD EventTotal=0;
WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
LPSOCKET_INFO   SocketArray[WSA_MAXIMUM_WAIT_EVENTS];

BOOL CreateSocketInfo(SOCKET s);
void FreeSocketInfo(DWORD Event);
BOOL CreateSocketInfo(SOCKET s)
{
LPSOCKET_INFO si;
if ((EventArray[EventTotal]=WSACreateEvent())==WSA_INVALID_EVENT)
{
printf("WSACreateEvent() failed with error %d\n", WSAGetLastError());
return FALSE;
}
if ((si=(LPSOCKET_INFO)GlobalAlloc(GPTR,sizeof(LPSOCKET_INFO)))==NULL)
{
printf("GlobalAlloc() failed with error %d\n", GetLastError());
return FALSE;
}

si->socket=s;
si->bytesRecv=0;
si->bytesSend=0;
SocketArray[EventTotal]=si;
EventTotal++;
return TRUE;
}
void FreeSocketInfo(DWORD Event)
{
LPSOCKET_INFO SI = SocketArray[Event];
DWORD i;
closesocket(SI->socket);
GlobalFree(SI);
WSACloseEvent(EventArray[Event]);
for (i = Event; i < EventTotal; i++)
{
EventArray[i] = EventArray[i + 1];
SocketArray[i] = SocketArray[i + 1];
}

EventTotal--;
}
int _tmain(int argc, _TCHAR* argv[])
{
WSAData wsadata;
DWORD ret;
SOCKET slisten;
SOCKET sClient;
SOCKADDR_IN listenaddr;
DWORD dwEvent;
DWORD Flags;
DWORD RecvBytes;
DWORD SendBytes;
WSANETWORKEVENTS NetworkEvents;
if ((ret=WSAStartup(MAKEWORD(2,2),&wsadata))!=0)
{
printf("WSAStartup() failed with error %d\n", ret); 
return 0;
}
    slisten=socket(AF_INET,SOCK_STREAM,0);
if (slisten==INVALID_SOCKET)
{
printf("socket() failed with error %d\n", ret);
return 0;
}
CreateSocketInfo(slisten);
//为事件关联套接字,以及感兴趣的网络时间
WSAEventSelect(slisten,EventArray[EventTotal-1],FD_ACCEPT|FD_CLOSE);
listenaddr.sin_family=AF_INET;
listenaddr.sin_port=htons(PORT);
listenaddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
if (bind(slisten, (PSOCKADDR)&listenaddr, sizeof(listenaddr)) == SOCKET_ERROR)
{
printf("bind() failed with error %d\n", WSAGetLastError());
return 0;
}
if (listen(slisten, 5))
{
printf("listen() failed with error %d\n", WSAGetLastError());
return 0;
}
while (TRUE)
{
//关联之后开始IO处理
if ((dwEvent=WSAWaitForMultipleEvents(EventTotal,EventArray,FALSE,WSA_INFINITE,FALSE))==WSA_WAIT_FAILED)
{
printf("WSAWaitForMultipleEvents failed with error %d\n", WSAGetLastError());
return 0;
}
//查询发生了什么网络事件
if (WSAEnumNetworkEvents(SocketArray[dwEvent-WSA_WAIT_EVENT_0]->socket, EventArray[dwEvent-WSA_WAIT_EVENT_0], &NetworkEvents) == SOCKET_ERROR)
{
printf("WSAEnumNetworkEvents failed with error %d\n", WSAGetLastError());
return 0;
}
if (NetworkEvents.lNetworkEvents&FD_ACCEPT)
{
if (NetworkEvents.iErrorCode[FD_ACCEPT_BIT] != 0)
{
printf("FD_ACCEPT failed with error %d\n", NetworkEvents.iErrorCode[FD_ACCEPT_BIT]);
break;
}
if ((sClient=accept(SocketArray[dwEvent-WSA_WAIT_EVENT_0]->socket,NULL,NULL)) == INVALID_SOCKET)
{
printf("accept() failed with error %d\n", WSAGetLastError());
break;
}
if (EventTotal > WSA_MAXIMUM_WAIT_EVENTS)
{
printf("Too many connections - closing socket.\n");
closesocket(sClient);
break;
}
CreateSocketInfo(sClient);
if (WSAEventSelect(sClient, EventArray[EventTotal - 1], FD_READ|FD_WRITE|FD_CLOSE) == SOCKET_ERROR)
{
printf("WSAEventSelect() failed with error %d\n", WSAGetLastError());
return 0;
}
printf("Socket %d connected\n", sClient);
}

//读取或者写入事件
if (NetworkEvents.lNetworkEvents & FD_READ|NetworkEvents.lNetworkEvents & FD_WRITE)
{
if (NetworkEvents.lNetworkEvents & FD_READ &&NetworkEvents.iErrorCode[FD_READ_BIT] != 0)
{
printf("FD_READ failed with error %d\n", NetworkEvents.iErrorCode[FD_READ_BIT]);
break;
}

if (NetworkEvents.lNetworkEvents & FD_WRITE&&NetworkEvents.iErrorCode[FD_WRITE_BIT] != 0)
{
printf("FD_WRITE failed with error %d\n", NetworkEvents.iErrorCode[FD_WRITE_BIT]);
break;
}
}
LPSOCKET_INFO SocketInfo=SocketArray[dwEvent-WSA_WAIT_EVENT_0];
//读取
if (SocketInfo->bytesRecv == 0)
{
SocketInfo->Databuf.buf = SocketInfo->Buffer;
SocketInfo->Databuf.len = DATA_BUFSIZE;
            Flags = 0;
if (WSARecv(SocketInfo->socket, &(SocketInfo->Databuf), 1, &RecvBytes,&Flags, NULL, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
printf("WSARecv() failed with error %d\n", WSAGetLastError());
FreeSocketInfo(dwEvent - WSA_WAIT_EVENT_0);
return 0;
}
} 
else
{
SocketInfo->bytesRecv=RecvBytes;
}
}
//写
if (SocketInfo->bytesRecv> SocketInfo->bytesSend)
{
SocketInfo->Databuf.buf = SocketInfo->Buffer + SocketInfo->bytesSend;
SocketInfo->Databuf.len = SocketInfo->bytesRecv - SocketInfo->bytesSend;
if (WSASend(SocketInfo->socket, &(SocketInfo->Databuf), 1, &SendBytes, 0,NULL, NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
printf("WSASend() failed with error %d\n", WSAGetLastError());
FreeSocketInfo(dwEvent - WSA_WAIT_EVENT_0);
return 0;
}
// A WSAEWOULDBLOCK error has occured. An FD_WRITE event will be posted
// when more buffer space becomes available
}
else
{
SocketInfo->bytesRecv += SendBytes;

if (SocketInfo->bytesSend==SocketInfo->bytesRecv)
{
SocketInfo->bytesRecv = 0;
SocketInfo->bytesSend = 0;
}
}
}
if (NetworkEvents.lNetworkEvents & FD_CLOSE)
{
if (NetworkEvents.iErrorCode[FD_CLOSE_BIT] != 0)
{
printf("FD_CLOSE failed with error %d\n", NetworkEvents.iErrorCode[FD_CLOSE_BIT]);
break;
}

printf("Closing socket information %d\n", SocketArray[dwEvent-WSA_WAIT_EVENT_0]->socket);
FreeSocketInfo(dwEvent-WSA_WAIT_EVENT_0);
}
  }
return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值