WSAEventSelect模型
来源:互联网 发布:编程教育 编辑:程序博客网 时间:2024/05/16 04:41
WSAEventSelect模型类似于WSAAsynSelect模型,但最主要的区别是网络事件发生时会被发送到一个事件对象句柄,而不是发送到一个窗口。该模式下编程步骤为:
【1】首先创建事件对象来接收网络事件。
WSAEVENT WSACreateEvent(void);
调用后返回事件对象句柄,初始状态为无信号且为手工重置事件,如果程序想使用自动重置事件则应使用CreateEvent()函数。
【2】注册网络事件
int WSAEventSelect(SOCKET s,WSAEVENT hEventObject,long lNetworkEvents);
此函数将事件对象hEventObject与套接字相关联,同时注册网络事件lNetworkEvent,当s上注册的网络事件发生时,对应的事件对象将收到信号。
【3】等待网络事件来触发事件句柄的状态
DWORD WSAWaitForMultipleEvent(DWORD cEvents,const WSAEVENT FAR* lphEvents,
bool fWaitAll,DWORD dwTimeout,BOOL fAlertable);
cEvents为事件句柄的数目,其最大值为WSA_MAXIMUM_WAIT_EVENTS,lphEvents为事件句柄数组的指针,fWaitAll指定等待类型,TRUE表示当lphEvents数组中所有事件对象都收到信号后才返回,FALSE表示只要任一事件对象收到信号就返回。dwTimeout为等待的超时时间(单位为毫秒)。fAlertable为指定函数返回时是否执行完成例程。对事件数组中的时间进行引用时,应该用WSAWaitForMutipleEvents()函数的返回值减去预声明值WSA_WAIT_EVENT_0作为数组下标,从而得到具体的引用值。
【4】判断网络事件类型
int WSAEnumNetworkEvents(SOCKET s,WSAEVENT hEventObject,LPWSANETWORKEVENTS lpNetworkEvents);
该函数用来指出在套接字s上发生的网络事件。参数s为套接字号,hEventObject是可选参数,用来指定需要重设的事件对象,lpNetworkEvents指向LPWSANETWORKEVENTS 结构的指针,该结构用于记录发生的网络事件和相关的错误代码。
【5】I/O处理后,应重置事件对象为无信号状态
BOOL WSAResetEvent(WSAEVENT hEvent);
【6】最后关闭事件对象句柄
实例代码:
#include <winsock2.h>
#include <stdio.h>
#define PORT 5150
#define MSGSIZE 1024
#pragma comment(lib, "ws2_32.lib")
int g_iTotalConn = 0;
SOCKET g_CliSocketArr[MAXIMUM_WAIT_OBJECTS];
WSAEVENT g_CliEventArr[MAXIMUM_WAIT_OBJECTS];
DWORD WINAPI WorkerThread(LPVOID);
void Cleanup(int index);
int main()
{
WSADATA wsaData;
SOCKET sListen, sClient;
SOCKADDR_IN local, client;
DWORD dwThreadId;
int iaddrSize = sizeof(SOCKADDR_IN);
// Initialize Windows Socket library
WSAStartup(0x0202, &wsaData);
// Create listening socket
sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Bind
local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
local.sin_family = AF_INET;
local.sin_port = htons(PORT);
bind(sListen, (struct sockaddr *)&local, sizeof(SOCKADDR_IN));
// Listen
listen(sListen, 3);
// Create worker thread
CreateThread(NULL, 0, WorkerThread, NULL, 0, &dwThreadId);
while (TRUE)
{
// Accept a connection
sClient = accept(sListen, (struct sockaddr *)&client, &iaddrSize);
printf("Accepted client:%s:%d/n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));
// Associate socket with network event
g_CliSocketArr[g_iTotalConn] = sClient;
g_CliEventArr[g_iTotalConn] = WSACreateEvent();
WSAEventSelect(g_CliSocketArr[g_iTotalConn],
g_CliEventArr[g_iTotalConn],
FD_READ | FD_CLOSE);
g_iTotalConn++;
}
}
DWORD WINAPI WorkerThread(LPVOID lpParam)
{
int ret, index;
WSANETWORKEVENTS NetworkEvents;
char szMessage[MSGSIZE];
while (TRUE)
{
ret = WSAWaitForMultipleEvents(g_iTotalConn, g_CliEventArr, FALSE, 1000, FALSE);
if (ret == WSA_WAIT_FAILED || ret == WSA_WAIT_TIMEOUT)
{
continue;
}
index = ret - WSA_WAIT_EVENT_0;
WSAEnumNetworkEvents(g_CliSocketArr[index], g_CliEventArr[index], &NetworkEvents);
if (NetworkEvents.lNetworkEvents & FD_READ)
{
// Receive message from client
ret = recv(g_CliSocketArr[index], szMessage, MSGSIZE, 0);
if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET))
{
Cleanup(index);
}
else
{
szMessage[ret] = '/0';
send(g_CliSocketArr[index], szMessage, strlen(szMessage), 0);
}
}
if (NetworkEvents.lNetworkEvents & FD_CLOSE)
{
Cleanup(index);
}
}
return 0;
}
void Cleanup(int index)
{
closesocket(g_CliSocketArr[index]);
WSACloseEvent(g_CliEventArr[index]);
if (index < g_iTotalConn - 1)
{
g_CliSocketArr[index] = g_CliSocketArr[g_iTotalConn - 1];
g_CliEventArr[index] = g_CliEventArr[g_iTotalConn - 1];
}
g_iTotalConn--;
}
- WSAEventSelect模型
- WSAEventSelect模型
- WSAEventSelect模型
- WSAEventSelect模型
- WSAEventSelect模型
- WSAEventSelect模型
- WSAEventSelect模型
- WSAEventSelect模型
- WSAEventSelect模型
- WSAEventSelect模型
- WSAEventSelect模型
- WSAEventSelect模型
- WSAEventSelect模型
- WSAEventSelect模型
- WSAEventSelect模型
- WSAEventSelect模型
- WSAEventSelect模型
- WSAEventSelect 模型
- 探索 == 快乐
- 如何解决内网IP端口不通的问题
- 插入排序
- bzoj4179: B
- 二叉搜索树的前序遍序序列 仿后序
- WSAEventSelect模型
- HTML5基础03----HTML5元素简介及使用方法
- WebRTC
- HDU3466
- 每天一个Linux命令-10(Linux find xargs详解)
- MapReduce的KeyValueTextInputFormat
- 最大子序列和的四种求解算法及其时间比较
- win7CMD route配置内外网双网卡操作
- HDU5308-脑补-对拍