==> 学习汇总(持续更新)
==> 从零搭建后端基础设施系列(一)-- 背景介绍


WSAEventSelect模型和WSAAsyncSelect模型
相同点:
1.都是由系统通知应用程序处理网络事件
2.都是异步的
不同点:通知机制不一样,WSAAsyncSelect模型是以windows的消息机制来通知应用程序的。WSAEventSelect模型是以事件形式通知的。所以一个需要窗口,一个则不需要。

建立WSAEventSelect模型步骤:

##1.为server socket创建网络事件对象和注册网络事件

用到的函数及原型如下:

创建网络事件对象

WSAEVENT  WSACreateEvent (void);

注册网络事件

int WSAEventSelect(     //成功返回0SOCKET s,             //要注册的socket WSAEVENT hEventObject,//网络事件对象long lNetworkEvents   //网络事件,FD_开头的
);

例如:

g_hServerEvent = WSACreateEvent();   //创建网络事件对象
WSAEventSelect(g_sServer, g_hServerEvent, FD_ACCEPT);//为server socket注册网络事件

如图:

##2.接受client请求线程

用到的结构、函数及原型如下:

网络事件结构体

typedef struct _WSANETWORKEVENTS {long lNetworkEvents;           //网络事件,FD_开头的int iErrorCode[FD_MAX_EVENTS]; //错误代码
} WSANETWORKEVENTS, *LPWSANETWORKEVENTS;

查找给定socket上发生的网络事件

int WSAEnumNetworkEvents(    //成功返回0SOCKET s,                WSAEVENT hEventObject,     //该socket的网络事件对象LPWSANETWORKEVENTS lpNetworkEvents //网络结构体指针
);

判断发生了哪个网络事件

networkEvents.lNetworkEvents & FD_ACCEPT 如果等于1 则表示发生了FD_ACCEPT事件

判断有无网络错误

networkEvents.iErrorCode[FD_ACCEPT_BIT]  等于0表示无错误

若无错误,则接受client请求,为新的client创建网络事件对象和注册网络事件。

如图:

##3.接收数据线程函数

用到的结构、函数及原型如下:

等待网络事件的到来

DWORD WSAAPI WSAWaitForMultipleEvents(DWORD cEvents,                //等待的事件数const WSAEVENT FAR* lphEvents,//事件对象数组BOOL fWaitAll,                //是否等待全部socket都有事件才返回DWORD dwTimeout,              //等待时间,毫秒为单位,WSA_INFINE表示无限期等待BOOL fAlertable               //先置为FALSE
);

这个函数会返回一个index,表示是第几个网络事件对象,根据这个index也可以索引到socket,然后下面调用WSAEnumNetworkEvents来判断该socket上发生了什么事件。

如图:

示例代码:

#include <WinSock2.h>
#include <process.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")SOCKET g_sClient[WSA_MAXIMUM_WAIT_EVENTS] = {INVALID_SOCKET};  //client socket数组
WSAEVENT g_event[WSA_MAXIMUM_WAIT_EVENTS];                     //网络事件对象数组
SOCKET g_sServer = INVALID_SOCKET;                             //server socket
WSAEVENT g_hServerEvent;                                       //server 网络事件对象
int iTotal = 0;                                                //client个数
/*
@function OpenTCPServer             打开TCP服务器
@param _In_ unsigned short Port     服务器端口
@param  _Out_ DWORD* dwError        错误代码
@return  成功返回TRUE 失败返回FALSE
*/
BOOL OpenTCPServer( _In_ unsigned short Port, _Out_ DWORD* dwError)
{BOOL bRet = FALSE;WSADATA wsaData = { 0 };SOCKADDR_IN ServerAddr = { 0 };ServerAddr.sin_family = AF_INET;ServerAddr.sin_port = htons(Port);ServerAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");do{if (!WSAStartup(MAKEWORD(2, 2), &wsaData)){if (LOBYTE(wsaData.wVersion) == 2 || HIBYTE(wsaData.wVersion) == 2){g_sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);g_hServerEvent = WSACreateEvent();                    //创建网络事件对象WSAEventSelect(g_sServer, g_hServerEvent, FD_ACCEPT);//为server socket注册网络事件 if (g_sServer != INVALID_SOCKET){if (SOCKET_ERROR != bind(g_sServer, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr))){if (SOCKET_ERROR != listen(g_sServer, SOMAXCONN)){bRet = TRUE;break;}*dwError = WSAGetLastError();closesocket(g_sServer);}*dwError = WSAGetLastError();closesocket(g_sServer);}*dwError = WSAGetLastError();}*dwError = WSAGetLastError();}*dwError = WSAGetLastError();} while (FALSE);return bRet;
}//接受client请求线程
unsigned int __stdcall ThreadAccept(void* lparam)
{WSANETWORKEVENTS networkEvents; //网络事件结构while (iTotal < WSA_MAXIMUM_WAIT_EVENTS)  //这个值是64{if (0 == WSAEnumNetworkEvents(g_sServer, g_hServerEvent, &networkEvents)){if (networkEvents.lNetworkEvents & FD_ACCEPT) //如果等于FD_ACCEPT,相与就为1{if (0 == networkEvents.iErrorCode[FD_ACCEPT_BIT])  //检查有无网络错误{//接受请求SOCKADDR_IN addrServer = { 0 };int iaddrLen = sizeof(addrServer);g_sClient[iTotal] = accept(g_sServer, (SOCKADDR*)&addrServer, &iaddrLen);if (g_sClient[iTotal] == INVALID_SOCKET){printf("accept failed with error code: %d\n", WSAGetLastError());return 1;}//为新的client注册网络事件g_event[iTotal] = WSACreateEvent();WSAEventSelect(g_sClient[iTotal], g_event[iTotal], FD_READ | FD_WRITE | FD_CLOSE);iTotal++;printf("accept a connection from IP: %s,Port: %d\n", inet_ntoa(addrServer.sin_addr), htons(addrServer.sin_port));}else  //错误处理{int iError = networkEvents.iErrorCode[FD_ACCEPT_BIT];printf("WSAEnumNetworkEvents failed with error code: %d\n", iError);return 1;}}}Sleep(100);}return 0;
}//接收数据
unsigned int __stdcall ThreadRecv(void* lparam)
{char* buf = (char*)malloc(sizeof(char) * 128);while (1){if (iTotal == 0){Sleep(100);continue;}//等待网络事件DWORD dwIndex = WSAWaitForMultipleEvents(iTotal, g_event, FALSE, 1000, FALSE); //当前的事件对象WSAEVENT curEvent = g_event[dwIndex];//当前的套接字SOCKET sCur = g_sClient[dwIndex];//网络事件结构WSANETWORKEVENTS networkEvents;if (0 == WSAEnumNetworkEvents(sCur, curEvent, &networkEvents)){if (networkEvents.lNetworkEvents & FD_READ)  //有数据可读{if (0 == networkEvents.iErrorCode[FD_READ_BIT]){memset(buf, 0, sizeof(buf));int iRet = recv(sCur, buf, sizeof(buf), 0);  //接收数据if (iRet != SOCKET_ERROR){if (strlen(buf) != 0)printf("Recv: %s\n", buf);}}else //错误处理{int iError = networkEvents.iErrorCode[FD_ACCEPT_BIT];printf("WSAEnumNetworkEvents failed with error code: %d\n", iError);break;}}else if (networkEvents.lNetworkEvents & FD_CLOSE)  //client关闭printf("%d downline\n", sCur);}Sleep(100);}if (buf)free(buf);return 0;
}int main()
{DWORD dwError = 0;if (OpenTCPServer(18000, &dwError)){_beginthreadex(NULL, 0, ThreadAccept, NULL, 0, NULL);_beginthreadex(NULL, 0, ThreadRecv, NULL, 0, NULL);}Sleep(100000000);closesocket(g_sServer);WSACleanup();return 0;
}

这里有个问题要说一下,就是WSAWaitForMultipleEvents可以无限期阻塞,但是最后不要这样,因为如果它阻塞在一个状态后,有新的client加入,它不知道,得不到更新,就算新的client发送消息,也不会返回,要等原来的client发送消息让它返回后才会处理新的client消息。所以我建议timeout时间设置为1s或几s都行,这样轮询消耗的CPU可以忽略不计。这个问题在Select模型的时候也有,Select也会阻塞在那里.

WSAEventSelect模型例子相关推荐

  1. 详细解析WSAEventSelect模型

    这个模型是一个简单的异步事件模型,使用起来比较方便,现在说一下其的具体的用法和需要注意的地方. 一,模型的例程(服务端): 先举一个王艳平网络通信上的例子: [cpp] view plaincopyp ...

  2. threejs加载3D模型例子

    加载3D模型 首先要引入ColladaLoader加载器,Collada是一个3D模型交换方案,即不同的3D模型可以通过Collada进行相互转换,言外之意,threejs可以使用Collada将3D ...

  3. WinSock I/O 模型 -- WSAEventSelect 模型

    简介 WSAEventSelect 模型也是 WinSock 中最常见的异步 I/O 模型. 这篇文章我们就来看看如何使用 WSAEventSelect api 来实现一个简单的 TCP 服务器. A ...

  4. 3ds Max建模,Blend设计,VS2008控制WPF的3D模型例子

    原文:3ds Max建模,Blend设计,VS2008控制WPF的3D模型例子 3ds Max建模,Blend设计,VS2008控制WPF的3D模型例子 所用的软件 3ds Max 9.0,Micro ...

  5. Windows套接字I/O模型(4) -- WSAEventSelect模型

    一.WSAEventSelect模型介绍 WSAEventSelect模型和WSAAsyncSelect模型类似,它也允许应用程序在一个或多个套接字上面,接收以事件为基础的网络事件通知.该模型和WSA ...

  6. MATLAB优化模型例子,MATLAB优化算法案例分析与应用(进阶篇)

    导语 余胜威编著的<MATLAB优化算法案例分析与应用(进阶篇)>基本包括了所有常见的MATLAB优化算法及应用,包括贝叶斯分类器.期望最大化算法.K最近邻密度估计.朴素贝叶斯分类器.背景 ...

  7. 套接字I/O模型之WSAEventSelect

    今天我又学习了一种新的套接字I/O模型------WSAEventSelect,他与WSAAsyncSelect一样也是一种异步事件通知模型,不同的是WSAAsyncSelect是与窗口句柄关联在一起 ...

  8. Winsock异步模式I/O模型WSAEventSelect的使用

    1.Winsock同步阻塞方式的问题 在异步非阻塞模式下,像accept(WSAAccept),recv(recv,WSARecv,WSARecvFrom)等这样的winsock函数调用后马上返回,而 ...

  9. CTR深度学习模型之 DIN(Deep Interest Network) 的理解与例子

    在电商领域,每个用户都有丰富的历史行为数据,这些数据具有如下特点: 多样性(Diversity):用户可能对多种商品感兴趣,例如手机.衣服. 局部激活(Local Activation):用户是否点击 ...

最新文章

  1. 用户控件和自定义控件
  2. 笔记-信息系统开发基础-面向对象基本概念-多态
  3. SEED实验系列:ShellShock 攻击实验
  4. solrcloud 7.5在k8s上的部署安装和使用教程
  5. 11gR2 集群(CRS/GRID)新功能—— SCAN(Single Client Access Name)
  6. java 字符串排序_Java控制台输入字符串及字符串比较
  7. nginx rtmp直播无延迟_Ubuntu中使用Nginx+rtmp搭建流媒体直播服务
  8. python办公自动化练习——体温
  9. Http协议/JSON格式
  10. linux怎样编译安装pidgin,Ubuntu 10.04编译安装Pidgin-2.7.3整个过程
  11. google aviator:Java逻辑公式引擎
  12. 九、CompletableFuture异步编排
  13. 双子天蝎,爱情是不老的传说
  14. Dubbo (二) ---------- Dubbo 框架
  15. 为什么用新浪邮箱收不到Github注册的验证邮件???
  16. 长江实业全新超甲级商业地标 长江集团中心二期设计理念以人为本
  17. Mac下将文件复制到移动硬盘
  18. SAP-FICO CO凭证的相关知识点
  19. Ubuntu安装升级glibc
  20. 许奔创新社-第17问:头脑风暴,我从一开始就错了吗?

热门文章

  1. mcafee的mysql audit认证插件的使用
  2. 海贼王游戏--EM游戏02--未雨绸缪
  3. 国内经常使用的网站访问统计系统比较
  4. TcaplusDB君 · 行业新闻汇编(四
  5. vex夹球机器人_Vex机器人软件使用说明书
  6. 毕业5年,年薪60万,我总结了职场最值钱的6句话!
  7. 基本排序算法python实现
  8. On hand QuantitiesTransaction Qantiites
  9. centOS 安装VScode
  10. 私人飞机已不稀奇…国内首颗私人卫星上天!耗费500万,未来可能开直播赚钱