C#使用Poll/Select实现多路I/O复用

在实际的应用中,如果全部采用异步的操作来,会增加代码的复杂程度,某些时候使用Poll/Select来实现单线程多路的I/O复用会更合适一些

一、Poll

原型函数

public bool Poll (  int microSeconds,  SelectMode mode )

1:客户端

private void Update(){if(socket == null){return;}if (socket.Poll(0, SelectMode.SelectRead)){byte[] readBuff = new byte[1024];int count = socket.Receive(readBuff);string recvStr = System.Text.Encoding.Default.GetString(readBuff, 0, count);text.text = recvStr;}}

注:

使用socket.Poll方法检查套接字是否有可读数据,超时时间为0,即立即返回 ,如果套接字有可读数据,则执行后续操作

设置为不阻塞模式(microSeconds 为0)。比起异步程序,代码简单的多,这是Read接收,还有发送SelectWrite

2:服务端

服务端一直检测监听Socket各个客户端Socket状态,如果收到消息就分别处理

class Main
{static Socket listenfd;static Dictionary<Socket, ClientState> clients = new Dictionary<Socket, ClientState>();public static void Main(string[] args){listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);IPAddress ipAdr = IPAddress.Parse("127.0.0.1");IPEndPoint ipEp = new IPEndPoint(ipAdr, 8888);listenfd.Bind(ipEp);listenfd.Listen(0);Console.WriteLine("[服务器]启动成功");while (true){//检查listenfdif (listenfd.Poll(0, SelectMode.SelectRead)){ReadListenfd(listenfd);}//检查clientfdforeach (ClientState s in clients.Values){Socket clientfd = s.socket;if (clientfd.Poll(0, SelectMode.SelectRead)){if (!ReadClientfd(clientfd)){break;}}}//防止CPU占用过高System.Threading.Thread.Sleep(1);}}public static void ReadListenfd(Socket listenfd){Console.WriteLine("Accept");//该方法就是如果接收到了客户端,就返回客户端Socket clientfd = listenfd.Accept();ClientState state = new ClientState();state.socket = clientfd;clients.Add(clientfd, state);}public static bool ReadClientfd(Socket clientfd){ClientState state = clients[clientfd];//接收int count = 0;try{count = clientfd.Receive(state.readBuff);}//抛出异常catch (SocketException ex){clientfd.Close();clients.Remove(clientfd);Console.WriteLine("Receive SocketException " +ex.ToString());return false;}//客户端数量为0if (count == 0){clientfd.Close();clients.Remove(clientfd);Console.WriteLine("Socket Close");return false;}//广播string recvStr = System.Text.Encoding.Default.GetString(state.readBuff,0, count);Console.WriteLine("Receive" + recvStr);string sendStr = clientfd.RemoteEndPoint.ToString() + ":" + recvStr;byte[] sendBytes = System.Text.Encoding.Default.GetBytes(sendStr);//循环给每个客户端发送消息foreach (ClientState cs in clients.Values){cs.socket.Send(sendBytes);}return true;}
}

注:

若没有收到客户端数据,服务端也一直在循环,浪费了CPU。Poll客户端也是同理,没有数据的时候还总在Update中检测数据

二、Select

原型函数

public static void Select(  IList checkRead,  IList check Write,  IList checkError,  int microSeconds )

checkRead:检测是否有可读Socket列表

checkWrite:检测是否有可写Socket列表

checkError:检测是否有出错

1:客户端

List<Socket> checkRead = new List<Socket>();private void Update(){if (socket == null){return;}checkRead.Clear();checkRead.Add(socket);Socket.Select(checkRead, null, null, 0);foreach (Socket socket in checkRead){byte[] readBuff = new byte[1024];int count = socket.Receive(readBuff);string recvStr = System.Text.Encoding.Default.GetString(readBuff, 0, count);text.text = recvStr;}}

注:

由于程序在Update中不停地检测数据,性能较差。商业上为了做 到性能上的极致,大多使用异步(或使用多线程模拟异步程序)。

2:服务端

class Class
{static Socket listenfd;static Dictionary<Socket, ClientState> clients = new Dictionary<Socket, ClientState>();public static void Main(string[] args){listenfd = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);IPAddress ipAdr = IPAddress.Parse("127.0.0.1");IPEndPoint ipEp = new IPEndPoint(ipAdr, 8888);listenfd.Bind(ipEp);listenfd.Listen(0);Console.WriteLine("[服务器]启动成功");List<Socket> checkRead = new List<Socket>();while (true){//填充checkRead列表checkRead.Clear();checkRead.Add(listenfd);foreach (ClientState s in clients.Values){checkRead.Add(s.socket);}//selectSocket.Select(checkRead, null, null, 1000);//检查可读对象foreach (Socket s in checkRead){if (s == listenfd){ReadListenfd(s);}else{ReadClientfd(s);}}}}public static void ReadListenfd(Socket listenfd){Console.WriteLine("Accept");//该方法就是如果接收到了客户端,就返回客户端Socket clientfd = listenfd.Accept();ClientState state = new ClientState();state.socket = clientfd;clients.Add(clientfd, state);}public static bool ReadClientfd(Socket clientfd){ClientState state = clients[clientfd];//接收int count = 0;try{count = clientfd.Receive(state.readBuff);}//抛出异常catch (SocketException ex){clientfd.Close();clients.Remove(clientfd);Console.WriteLine("Receive SocketException " +ex.ToString());return false;}//客户端数量为0if (count == 0){clientfd.Close();clients.Remove(clientfd);Console.WriteLine("Socket Close");return false;}//广播string recvStr = System.Text.Encoding.Default.GetString(state.readBuff, 0, count);Console.WriteLine("Receive" + recvStr);string sendStr = clientfd.RemoteEndPoint.ToString() + ":" + recvStr;byte[] sendBytes = System.Text.Encoding.Default.GetBytes(sendStr);//循环给每个客户端发送消息foreach (ClientState cs in clients.Values){cs.socket.Send(sendBytes);}return true;}

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

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

相关文章

web服务架构

1 Web服务器&#xff08;如Nginx、Apache等&#xff09;和Web应用框架&#xff08;如Flask、Django等&#xff09; Web服务器&#xff08;如Nginx、Apache等&#xff09;和Web应用框架&#xff08;如Flask、Django等&#xff09;在Web应用开发和部署中扮演着不同的角色&#xf…

python turtle库简单应用题

三角形 import turtle for i in range(3):turtle.seth(i * 120)turtle.fd(100) turtle.done()矩形 import turtle angle 90 for x in range(4):turtle.fd(100)turtle.seth(angle)angle 90 turtle.done()五边形 import turtle angle 360/5 for x in range(5):turtle.fd(10…

软考中级 --网络工程师真题试卷 2023下半年

在EIGRP协议中&#xff0c;某个路由器收到了两条路径到达目标网络&#xff0c;路径1的带宽为100Mbps&#xff0c;延迟2ms&#xff0c;路径2的带宽为50Mbps&#xff0c;迟为4ms&#xff0c;如果EIGRP使用带宽和延迟的综合度量标准&#xff0c;那么该路由器选择的最佳路径是(D)。…

Codeforces Round 930 (Div. 2)(A,B,C,D)

比赛链接 C是个交互&#xff0c;D是个前缀和加二分。D还是很难写的。 A. Shuffle Party 题意&#xff1a; 您将得到一个数组 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1​,a2​,…,an​ 。最初&#xff0c;每个 1 ≤ i ≤ n 1 \le i \le n 1≤i≤n 对应 a i i a_ii…

你用对const了吗?C++中const小结

const 修饰普通变量 表示变量的值不能被改变。下面两条语句(第2行和第3行)表示的意思一致。 int a; const int ca 42; //int const ca 42;const 修饰指针 指向常量的指针不能改变其指对象的值。第 5 行代码是错误的。 int a 42;const int * ip &a; int const * ipp…

win10 禁止谷歌浏览器自动更新(操作贼简单)

禁止谷歌浏览器自动更新 &#xff08;1&#xff09;修改 "C:\Windows\System32\drivers\etc\hosts 文件&#xff0c;在最后增加 127.0.0.1 update.googleapis.com&#xff08;2&#xff09;保存后&#xff0c;winr 快捷键&#xff0c;输入cmd &#xff0c;打开命令行 &am…

RK3588 rknpu2及rknn-toolkit2使用说明

RKNN模型推理共有四种方式&#xff1a; 第一种是借助RKNN-Toolkit2的功能在模拟NPU上运行RKNN模型并获取推理结果&#xff08;在PC端&#xff09; 第二种是借助RKNN-Toolkit2的功能, 将板子与PC连接&#xff0c;将RKNN模型分发到指定的NPU设备进行推理并获取推理结果&#xff0…

AJAX踩坑指南(知识点补充)

JWT JSON Web Token是目前最为流行的跨域认证解决方案 如何获取&#xff1a;在使用JWT身份验证中&#xff0c;当用户使用其凭据成功登录时&#xff0c;将返回JSON Web Token(令牌&#xff09; Token本质就是一个包含了信息的字符串 如何获取Token:登录成功之后&#xff0c;服务…

Springboot解决跨域问题方案总结(包括Nginx,Gateway网关等)

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 目录 前言 解决跨域问题方案 1.Spring Boot 中解决跨域 1.1 通过注解跨域 1.2 通…

什么是RabbitMQ的死信队列

RabbitMQ的死信队列&#xff08;Dead Letter Queue&#xff0c;简称DLQ&#xff09;是一种用于处理消息失败或无法路由的消息的机制。它允许将无法被正常消费的消息重新路由到另一个队列&#xff0c;以便稍后进行进一步处理、分析或排查问题。 当消息对立里面的消息出现以下几…

C语言经典面试题目(二十七)

1、什么是头文件&#xff1f;为什么在C语言中需要使用头文件&#xff1f; 头文件是C语言中的一种文件&#xff0c;通常以.h为文件扩展名&#xff0c;用于存放函数声明、宏定义、结构体声明等。在C语言中&#xff0c;头文件的主要作用是将程序的接口与实现分离开来&#xff0c;…

大数据的实时计算和离线计算你理解吗?

不管是实时计算还是离线计算&#xff0c;都有着同样的业务目标&#xff0c;那就是根据业务要求把数据源计算处理成业务需要的直接可用的数据结果。 如果把数据源比作是水龙头里的水&#xff0c;把数据计算比作是生产纯净水的过程&#xff1b;那么实时计算就是用一根水管接在水龙…

css的text-shadow详解

CSS的text-shadow属性用于为文本添加阴影效果&#xff0c;以增强文本的立体感和印刷品质感。该属性可以接受多个值&#xff0c;每个值通过空格分隔&#xff0c;以定义阴影的各个方面。以下是text-shadow属性的详细介绍&#xff1a; 阴影颜色 (Color): 这是阴影的颜色值。它可以…

深度学习基础之《TensorFlow框架(10)—案例:实现线性回归(2)》

增加其他功能 一、增加变量显示 1、目的&#xff1a;在TensorBoard当中观察模型的参数、损失值等变量值的变化 2、收集变量 不同的变量要用不同的方式收集 &#xff08;1&#xff09;tf.summary.scalar(name, tensor) 收集对于损失函数和准确率等单值变量&#xff0c;name为…

ES6生成器(Generator)

一、function* 概念简介&#xff1a;function* - JavaScript | MDN (mozilla.org) function* 声明创建一个绑定到给定名称的新生成器函数。生成器函数可以退出&#xff0c;并在稍后重新进入&#xff0c;其上下文&#xff08;变量绑定&#xff09;会在重新进入时保存。 1.1 y…

Spring Boot 自动化单元测试类的编写过程

前言 Web环境模拟测试 企业开发不仅要保障业务层与数据层的功能安全有效&#xff0c;也要保障表现层的功能正常。但是我们一般对表现层的测试都是通过postman手工测试的&#xff0c;并没有在打包过程中代码体现表现层功能被测试通过。那么能否在测试用例中对表现层进行功能测…

LabVIEW高效光伏数据监控与管理系统

LabVIEW高效光伏数据监控与管理系统 随着新能源技术的发展&#xff0c;光伏发电系统作为一种清洁、高效的能源获取方式受到了广泛的关注。但是&#xff0c;由于光伏发电的特性受到多种环境因素的影响&#xff0c;其运行效率和安全性成为了关键问题。因此&#xff0c;开发一个高…

K8S--SpringCloud应用整合Nacos实战

原文网址&#xff1a;K8S--SpringCloud应用整合Nacos实战-CSDN博客 简介 本文介绍K8S部署SpringCloud应用整合Nacos实战。 本文是将原来的SpringCloud项目&#xff08;闪速优选&#xff09;迁移到K8S上&#xff0c;一行代码都不需要改动。用K8S运行Nacos、Gateway、SpringCl…

MTU网络大小

MTU是路由器最大传输单元&#xff08;指L3网络层最大帧大小&#xff09;&#xff0c;IP包超过这个MTU大小设定就会走分片流程&#xff0c;MTU最大为1500字节。 对于IPV4最小MTU要求至少68字节&#xff08;IP头占用大小&#xff0c;不包含其它载荷数据&#xff09; 对于IPV6最小…

Mac nvm install failed python: not found

报错 $>./configure --prefix/Users/xxx/.nvm/versions/node/v12.22.12 < ./configure: line 3: exec: python: not found nvm: install v12.22.12 failed!解决方法 到 App 文件夹&#xff0c;并且打开 cd /System/Applications/Utilities/ open .记得改完 Rosetta 之…