【面试题】网络IO多路复用模型之异步事件

目录

异步事件模型的概念

工作流程:

WSAEventSelect模型的优势和不足

代码:


异步事件模型的概念

WSAEventSelect模型是WindowsSockets提供的另外一个有用的异步I/O模型。该模型允许一个或多个套接字上接收以事件为基础的网络事件通知。Windows Sockets应用程序在创建套接字后,调用WSAEventSlect()函数,将一个事件对象与网络事件集合关联在一起。当网络事件发生时,应用程序以事件的形式接收网络事件通知。

工作流程:

1.通过WSAEventSelect()函数 向windows注册

2.监测事件什么时候有信号WSAWaitForMultipleEvents ()

3.判断发生的是什么网络事件WSAEnumNetworkEvents()

4.根据发生的事件进行相应的处理

WSAEventSelect模型的优势和不足

优势:可以在一个非窗口的Windows Sockets程序中,实现多个套接字的管理。性能较优

不足:

1.每个WSAEventSelect模型最多只能管理64个套接字。当应用程序中需要管理多于64个套接字时,就需要额外创建线程。

2.由于使用该模型开发套接字应用程序需要调用几个相关函数才能完成。因此,该模型增加了开发的难度,增加了开发人员的编码量。从这个角度讲,该模型不如WSAAysnceSelect模型方便。

代码:

TCPServer.h

#ifndef TCPSERVER_H
#define TCPSERVER_H
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <list>
#include <windows.h>
#include <map>
//#define MAXNUM  64
const int MAXNUM = 64;//socket----包大小、缓冲区、偏移量
struct SocketInfo{int nPackSize;char *pszbuf;int offset;
};
class TCPServer
{
public:TCPServer();~TCPServer();
public://1.初始化网络--加载、创建socket\bind\listenbool initNetWork(const char* szip = "127.0.0.1",unsigned short nport = 1234);void unInitNetWork(const char* szerr = "null"); //卸载网络bool sendData(SOCKET sockWaiter,const char* szbuf,int nlen); //向指定客户端发送数据void recvData(); //接收数据static DWORD WINAPI threadProc(LPVOID lpvoid);
private:SOCKET m_socklisten;std::list<HANDLE> m_lstThread;bool  m_bFlagQuit;std::map<DWORD,SOCKET> m_mapThreadIdToSocket;SOCKET m_arysocket[MAXNUM];HANDLE m_aryEvent[MAXNUM];int    m_nEventNum;std::map<SOCKET,SocketInfo*> m_mapSocketToInfo;
};#endif // TCPSERVER_H

TCPServer.cpp

#include "tcpserver.h"TCPServer::TCPServer()
{m_socklisten = 0;m_bFlagQuit = true;m_nEventNum = 0;ZeroMemory(m_aryEvent,sizeof(m_aryEvent));ZeroMemory(m_arysocket,sizeof(m_arysocket));
}TCPServer::~TCPServer()
{}bool TCPServer::initNetWork(const char *szip, unsigned short nport)
{//1.选择种类  韩餐 火锅  串串香   川菜 -- 加载库WORD wVersionRequested;WSADATA wsaData;int err;/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */wVersionRequested = MAKEWORD(2, 2);err = WSAStartup(wVersionRequested, &wsaData);if (err != 0) {/* Tell the user that we could not find a usable *//* Winsock DLL.                                  */printf("WSAStartup failed with error: %d\n", err);return false;}/* Confirm that the WinSock DLL supports 2.2.*//* Note that if the DLL supports versions greater    *//* than 2.2 in addition to 2.2, it will still return *//* 2.2 in wVersion since that is the version we      *//* requested.                                        */if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {/* Tell the user that we could not find a usable *//* WinSock DLL.                                  */printf("Could not find a usable version of Winsock.dll\n");unInitNetWork();return false;}elseprintf("The Winsock 2.2 dll was found okay\n");//2.雇人-店长--m_socklisten = socket(AF_INET,SOCK_STREAM,0);if(m_socklisten == INVALID_SOCKET){unInitNetWork("socket err");return false;}//3.选择地址--sockaddr_in addrserver;addrserver.sin_family = AF_INET;addrserver.sin_addr.S_un.S_addr = inet_addr(szip);addrserver.sin_port = htons(nport);if( SOCKET_ERROR == bind(m_socklisten,(sockaddr*)&addrserver,sizeof(addrserver))){unInitNetWork("bind err");return false;}//4.宣传--if( SOCKET_ERROR == listen(m_socklisten,1000)){ //  1_1_1_1______unInitNetWork("listen err");return false;}HANDLE  hevent = WSACreateEvent(); //默认人工 匿名无信号事件if(0 ==WSAEventSelect(m_socklisten,hevent,FD_ACCEPT)){//注册成功m_arysocket[m_nEventNum] = m_socklisten;m_aryEvent[m_nEventNum] = hevent;++m_nEventNum;}//    //创建接收连接的线程HANDLE hThread = CreateThread(0,0,&threadProc,this,0,0);if(hThread)m_lstThread.push_back(hThread);return true;
}DWORD TCPServer::threadProc(LPVOID lpvoid)
{TCPServer *pthis = (TCPServer*)lpvoid;DWORD dwIndex;WSANETWORKEVENTS wwe;sockaddr_in addrclient;int nsize = sizeof(addrclient);while(pthis->m_bFlagQuit){//等事件,判断哪个事件有信号dwIndex =WSAWaitForMultipleEvents(pthis->m_nEventNum, //事件的个数pthis->m_aryEvent, //监听事件的数组FALSE,//任意一个有信号就返回WSA_INFINITE,//等待时间0);dwIndex -=WSA_WAIT_EVENT_0;//判断发生什么事了if(WSAEnumNetworkEvents(pthis->m_arysocket[dwIndex],pthis->m_aryEvent[dwIndex],&wwe))continue;// 处理if(wwe.lNetworkEvents & FD_ACCEPT){printf("wait client connect......\n");SOCKET sockWaiter = accept(pthis->m_socklisten,(sockaddr*)&addrclient,&nsize);printf("client ip:%s port:%d\n",inet_ntoa(addrclient.sin_addr),addrclient.sin_port );//向windows注册HANDLE  hEvent = WSACreateEvent();if( 0==WSAEventSelect(sockWaiter,hEvent,FD_READ|FD_CLOSE)){pthis->m_aryEvent[pthis->m_nEventNum] =hEvent;pthis->m_arysocket[pthis->m_nEventNum] = sockWaiter;++pthis->m_nEventNum;}}if(wwe.lNetworkEvents & FD_READ){SocketInfo *p =   pthis->m_mapSocketToInfo[pthis->m_arysocket[dwIndex]];if(p == NULL){p = new SocketInfo;p->nPackSize =0;p->offset =0;p->pszbuf = NULL;//接收包大小int nReadNum = recv(pthis->m_arysocket[dwIndex],(char*)&p->nPackSize,sizeof(int),0);if(nReadNum >0){p->pszbuf = new char[p->nPackSize];}pthis->m_mapSocketToInfo[pthis->m_arysocket[dwIndex]] = p;}else{//接收包数据int nReadNum = recv(pthis->m_arysocket[dwIndex],p->pszbuf+p->offset,p->nPackSize,0);if(nReadNum>0){p->offset+=nReadNum;p->nPackSize-=nReadNum;if(p->nPackSize ==0){//todoprintf("client say:%s\n",p->pszbuf);delete []p->pszbuf;pthis->m_mapSocketToInfo[pthis->m_arysocket[dwIndex]] = NULL;}}}}if(wwe.lNetworkEvents & FD_CLOSE){closesocket(pthis->m_arysocket[dwIndex]);WSACloseEvent(pthis->m_aryEvent[dwIndex]);if(pthis->m_nEventNum >1){pthis->m_aryEvent[dwIndex] = pthis->m_aryEvent[pthis->m_nEventNum-1];pthis->m_arysocket[dwIndex] = pthis->m_arysocket[pthis->m_nEventNum-1];}--pthis->m_nEventNum;}}return 0;
}void TCPServer::unInitNetWork(const char* szerr )
{printf(szerr);if(m_socklisten){closesocket(m_socklisten);m_socklisten = 0;}WSACleanup();//结束所有的线程m_bFlagQuit = false;auto ite = m_lstThread.begin();while(ite !=m_lstThread.end()){//判断线程状态if(WAIT_TIMEOUT == WaitForSingleObject(*ite,100))TerminateThread(*ite,-1);CloseHandle(*ite);*ite = NULL;++ite;}m_lstThread.clear();
}bool TCPServer::sendData(SOCKET sockWaiter, const char *szbuf, int nlen)
{//发送的包大小if(send(sockWaiter,(const char*)&nlen,sizeof(int),0) <=0)return false;//发送包内容if(send(sockWaiter,szbuf,nlen,0) <=0)return false;return true;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/40249.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

面试专区|【40道移动端测试高频题整理(附答案背诵版)】

iOS应用和Android应用测试有什么侧重点&#xff1f; iOS应用和Android应用测试的侧重点略有不同&#xff0c;主要表现在以下几个方面&#xff1a; 分辨率和屏幕尺寸&#xff1a;Android设备的分辨率和屏幕尺寸多种多样&#xff0c;因此&#xff0c;需要测试更多的分辨率和屏幕…

2.Mybatics_映射器与参数

文章目录 映射器与参数一.XML映射器1.创建工具类2.SQL语句操作:3.模糊查询4.返回多个聚合函数的结果5.返回分组后的结果 二.不同个数参数的处理1.单个参数2.对象参数3.多个参数4.传入一个map类型的参数5.添加注册方法引出service层概念 映射器与参数 一.XML映射器 1.创建工具…

Android系统层屏蔽弹出停止运行对话框

项目场景&#xff1a; 车载项目&#xff0c;ATC8257-Android9.0系统平台&#xff0c;福田汽车P3系列项目 项目使用高德公版地图前提是无法获得任何高德定制服务&#xff0c;每次刷完机去切换语言系统会弹出"高德地图已停止运行"弹窗&#xff0c;严重影响用户使用体…

【第三版 系统集成项目管理工程师】第6章 数据工程

持续更新。。。。。。。。。。。。。。。 【第三版】第六章 数据工程 6.1数据采集和预处理6.1.1 数据采集 P2346.1.2 数据预处理6.1.3 数据预处理方法1.缺失数据的预处理-P2352.异常数据的预处理-P2363.不一致数据的预处理-P2364.重复数据的预处理-P2365.格式不符数据的预处理…

面经总结dd

java基础: 为什么重写hashcode和equals? hash码由对象的内存地址或者对象的属性计算而出,可以作为键值对的键例如hashmap中的key通过hashcode高低位异或计算比如在hashmap中,hashcode是确定桶的位置,然后通过equals()方法找到正确的对象,即认为不同的对象有着相同的桶(…

Perl 循环

Perl 循环 Perl 是一种功能强大的编程语言,广泛用于文本处理、系统管理、网络编程等领域。在 Perl 中,循环是控制程序流程的关键组成部分,它允许我们重复执行代码块,直到满足特定的条件。本文将详细介绍 Perl 中的各种循环结构,包括 for 循环、while 循环、until 循环、f…

uniApp 封装VUEX

Vuex Store (index.js) import Vue from vue; import Vuex from vuex; import Cookies from js-cookie;Vue.use(Vuex);const saveStateKeys [vuex_user, vuex_token, vuex_demo];const initialState {vuex_user: { name: 用户信息 },vuex_token: Cookies.get(token) || ,vue…

UE5 03-物体碰撞检测

在你需要碰撞的物体上添加一个碰撞检测组件 碰撞预设 设置为NoCollision,这样移动过程中就不会有物理碰撞阻挡效果,只负责检测是否碰撞,比较难解释,如果学过Unity的话,可以把它理解成 Collision 为 Trigger

My sql 安装,环境搭建

以下以MySQL 8.0.36为例。 一、下载软件 1.下载地址官网&#xff1a;https://www.mysql.com 2. 打开官网&#xff0c;点击DOWNLOADS 然后&#xff0c;点击 MySQL Community(GPL) Downloads 3. 点击 MySQL Community Server 4.点击Archives选择合适版本 5.选择后下载第二个…

密码学复习

目录 基础 欧拉函数 欧拉函数φ(n)定义 计算方法的技巧 当a=a_1*a_2*……*a_n时 欧拉定理 剩余系 一些超简单密码 维吉尼亚 密钥fox 凯撒(直接偏移) 凯特巴氏(颠倒字母表) 摩斯密码(字母对应电荷线) 希尔(hill)密码 一些攻击 RSA 求uf+vg=1 快速幂模m^…

Python | Leetcode Python题解之第213题打家劫舍II

题目&#xff1a; 题解&#xff1a; class Solution:def rob(self, nums: List[int]) -> int:def robRange(start: int, end: int) -> int:first nums[start]second max(nums[start], nums[start 1])for i in range(start 2, end 1):first, second second, max(fi…

Bootstrap 图片

Bootstrap 图片 Bootstrap 是一个流行的前端框架,它提供了一套丰富的工具和组件,用于快速开发响应式和移动优先的网页。在本文中,我们将探讨如何使用 Bootstrap 来处理和展示图片,包括图片的响应式设计、图片样式和图片布局。 响应式图片 Bootstrap 通过其栅格系统提供了…

人工智能在物流领域的应用,智慧物流大有可为!

物流是复合型服务产业&#xff0c;作为经济的重要组成部分&#xff0c;受到人工智能技术的深刻影响。物流行业的人工智能应用也将助推人工智能技术的发展&#xff0c;人工智能技术应用于物流行业&#xff0c;应用领域包括以下方向&#xff1a; 第一、车货匹配系统 使用人工智…

CSS弹性布局:打造响应式与灵活的网页设计

一、弹性布局是什么&#xff1f; 弹性布局&#xff08;Flexbox&#xff09;是一种CSS布局模型&#xff0c;它提供了一种更加高效的方式来对容器中的项目进行布局、对齐和分配空间。与传统的布局方式相比&#xff0c;Flexbox旨在提供一个更加灵活的方式来布局复杂的网页结构&am…

AI智能音箱用2×15W立体声功放芯片NTP8918

智能音箱是近年来非常受欢迎的智能家居产品之一&#xff0c;它集成了人工智能技术和音频技术&#xff0c;能够为用户提供语音助手、音乐播放、智能家居控制等多种功能。其中&#xff0c;音频输出是智能音箱的核心功能之一&#xff0c;而功放芯片则是实现音频放大的关键组成部分…

00 如何根据规律在变化中求发展?

你好&#xff0c;我是周大壮。目前&#xff0c;我已在搜索推荐等算法技术领域从事研发近 10 年&#xff0c;做过诸多流量分发领域的算法技术工作。 如今任公司同城的算法架构师、技术委员会人工智能分会委员、公司本地服务事业群算法策略部负责人&#xff0c;我主要负责公司集…

计算机网络之局域网

目录 1.局域网的基本概念 2.LAN的特性 3.局域网特点 4.拓扑结构 5.传输媒体的选择 6.传输媒体 7.传输技术 8.传输技术距离问题 9.LAN的逻辑结构 10.局域网工作原理 上篇文章内容&#xff1a;OSI七层体系结构 1.局域网的基本概念 局域网 是将分散在有限地 理范围内&…

51单片机定时器/计数器

欢迎入群共同学习交流 时间记录&#xff1a;2024/7/3 一、电路原理图 51单片机具有两个定时器T0、T1 二、知识点介绍 1、寄存器介绍 &#xff08;1&#xff09;TMOD方式寄存器 T0为例介绍&#xff1a; 工作方式选择位M1、M0 常用方式为方式1、方式2&#xff0c;方式2低…

【按键精灵】#1找图、找色、移动和点击

关键字&#xff1a; 找图、找色、移动和点击 找图&#xff1a; 抓抓截图&#xff0c;添加到附件 FindPic 0,0,1024,768,"Attachment:\Xmind.bmp",0.9,intX,intYIf intX > 0 And intY > 0 Then TracePrint "找到了" //找到打印Else TracePri…

深入解析Dubbo架构层次

什么是Dubbo&#xff1f; Dubbo是阿里巴巴开源的一款高性能优秀的服务框架&#xff0c;致力于提供高性能和透明化的 RPC 远程服务调用方案&#xff0c;以及 SOA 服务治理方案。它的主要功能包括&#xff1a; 远程通信&#xff1a;提供高效的远程通信能力。负载均衡&#xff1…