五种IO模型以及select多路转接IO模型

news2024/10/2 6:41:04

目录

一、典型IO模型

 1.1 阻塞IO

1.2 非阻塞IO

1.3 信号驱动I0

1.4 IO多路转接

 1.5 异步IO

多路转接的作用和意义

二、多路转接IO模型(select)

2.1 接口

 2.2 接口当中的事件集合: fd_set

2.2  select使用事件集合(位图)的方式

2.2.1 接口

2.3 select使用方式:

2.4 select的返回值:(有点反人类)

2.5 select的测试代码:

三、 用select来实现单个线程接收多个客户端


一、典型IO模型

 1.1 阻塞IO

在内核将数据准备好之前,系统调用会一直等待,直到数据的到来,拷贝完成数据后,IO调用才会返回

  • 1.2 非阻塞IO

  • 如果内核还未将数据准备好,系统调用仍然会直接返回,并且返回EWOULDBLOCK错误码。非阻塞IO的返回,需要判断系统调用函数的返回值,来判断当前函数是否将IO功能完成。
  • 1.没完成:一般会搭配循环继续调用(IO功能没有完成),但是这样对于CPU的资源也是巨大的浪费。
  • 2.完成了:内核将数据准备好了,拷贝回来了(IO功能完成)

  • 1.3 信号驱动I0

  • (就像是鱼竿上面绑了个铃铛)
  • 内核将数据准备好的时候,使用SIGIO信号通知应用程序进行I0操作。这里例如我们对于僵尸进程(僵尸进程就是子进程先于父进程退出,子进程的退出信息没有人回收)的处理可以配合信号当子进程退出的时候我们自定义信号的处理方式。调用wait函数来回收子进程

  • 1.4 IO多路转接

  • 我们首先来看一个场景

上面那种无脑创建进程、线程的方法是不能处理大量客户端的情况的。那怎么来解决呢?

需要使用多路转接

多路转接IO模型可以帮我们同时监控多个文件描述符

 有了多路转接,就可以不用无脑的创建线程或者进程了

就好比钓鱼的时候雇人去钓鱼,如果说哪个鱼竿上鱼了,让他别动,我们去享受把鱼拽上来的快感

  •  1.5 异步IO

  • 由内核在数据拷贝完成时,通知应用程序(而信号驱动是告诉应用程序何时可以开始拷贝数据)。好比说钓鱼,信号IO就是相当于鱼竿上面帮了一个铃铛,铃铛响了的时候通知你来将鱼竿收起然后钓鱼,而异步IO则是帮你钓鱼,就是帮你找了一个人当他调好了鱼之后来通知你取鱼

 同步IO和异步IO的最大区别就是:

异步IO啥事也不管,只是告诉你我要做这件事情,接下来这件事情由你来做(你怎么多久是你的事情),做完你再告诉我

多路转接的作用和意义

1、作用:IO多路转接可以帮助我们同时等待多个文件描述符的就绪状态,多路转接IO模型可以帮助我们同时监控多个文件描述符

 2、多路转接IO模型,就是程序高并发的基础

高并发:  程序可以处理大量的客户端请求

3、扩展:一个好的程序,需要考量高并发,也需要考量高可用

高可用:就说不管程序遇到什么糟糕场景,都是可以使用的,比如程序挂掉了(备份进程)(守护进程)

二、多路转接IO模型(select)

  • 2.1 接口

  • int select(int nfds, fd_set  *readfds, fd_set  *writefds,fd_set  *exceptfds, struct timeval  *timeout);

nfds :取值为最大文件描述符的数值+1,作用是:控制select的轮询监控范围。

  • fd_set   :  事件集合
  • readfds :    读事件集合
  • writefds:  写事件集合
  • exceptfds:异常事件集合

timeout  :  表示工作方式

  • 阻塞方式 : NULL
  • 非阻塞     : 0
  • 带有超时时间的监控:传递struct  timeval 这样的结构体对象

  • 返回值:
  • 成功:返回就绪文件描述符的个数
  • 失败:返回-1,并且设置了errno,程序员就可以通过perror这个函数查看失败原因

 2.2 接口当中的事件集合: fd_set

 第一印象:

        fd_set :  是一个结构体,结构体当中有一个数组,名字为fds_bits

探究:

  • 1.   数据的元素类型是什么?
  • 2.数据的元素个数为多少?

 我们可以发现,数组的大小只有16个,这就很奇怪了,如果一个元素存放一个文件描述符数值,那最多也才16个,这肯定是不对的,太少了,一个进程随随便便就会有很多个文件描述符。

那到底是什么回事呢?

事件集合的使用方式并不是按照数组的方式来使用的,而是按照比特位(位图)的方式使用的

2.2  select使用事件集合(位图)的方式

2.2.1 接口

  • void FD_CLR(int fd,fd_set *set) ;
    • 作用:将fd从事件集合set当中去除掉,本质就是将fd对应的比特位置为0
  • int FD_ISSET(int fd,fd_set *set) ;
    • 作用:判断fd文件描述符,是否在set集合当中,本质是判断fd对应的比特位是否为0
    • 返回值:
    • 0:表示fd不在set当中
    • 1:表示fd在set当中
  • void FD_SET(int fd,fd_set *set) ;
    • 作用:设置fd文件描述符到set事件集合当中,本质是将fd对应的比特位设置为1
  • void FD_ZERO(fd_set *set) ;
    • 作用:清空事件集合.本质是将set当中所有的比特位都置为0

例子:

  • 2.3 select使用方式:

  • 1..select共有三个事件集合:读事件集合,写事件集合,异常事件集合。
  • 2.当需要关注某个文件描述符的某个事件,则将来个文件描述符添加到对应的事件集合当中。例如:关注(0号文件描述符的读事件,则将0号文件描述符添加到读事件集合当中readfds。
  • 3.如果不关注某种事件,则给select传递参数的时候,传递NULL。

  • 2.4 select的返回值:(有点反人类)

  • 1.返回值为就绪的文件描述符的个数
  • 2.就绪的文件描述符存储在事件集合当中返回给调用者

但是:没有就绪的文件描述符呢?也放在事件集合当中吗?

肯定不会,因为select监控成功完事件集合之后,还是要判断哪些文件描述符就绪了,为了能够判断出来,就需要将未就绪的除掉

 所以,如果select监控成功之后,再次需要监控时,需要将上一次未就绪的文件描述符给他放到事件集合当中去

  • 2.5 select的测试代码:

代码:

 

 

 之前是阻塞在scanf的等待读过程,我们看看用到了select进行监控,这个进程阻塞在哪里:

  • 三、 用select来实现单个线程接收多个客户端

  • 我们知道如果没有多路转接io的话那么就要用多线程来处理接收多个客户端连接服务端。那么这里我们就可以实现用一个线程来实现接收多个客户端的连接。

改造前:

        accept 放到while 循环的外面,这个进程一辈子只能接收一个客户端的连接

        accept 放到while 循环的外面,这个进程一辈子只能和客户端联系一次(但是可以和多个客户端发送数据)  

改造后:

        思路: select 帮助我们监控listen_sockfd(一个),new_sockfd(多个)

                   当select监控成功之后,我们针对不同的文件描述符做出不同的操作

                   listen_sockfd (读事件) :accept

                   new_sockfd (读事件):recv     

服务端:

客服端:

 运行一下观察结果:

 可以看到,一个线程就能处理多态客户端,属实是神奇!!!

四、select的优缺点

4.1优点:

4.2缺点

 

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

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

相关文章

ip公司和soc公司是什么?

IP 公司和 SoC 公司都是半导体行业的重要组成部分,但它们的角色和职责略有不同。IP(Intellectual Property)公司主要提供可重用的知识产权组件,也称为 IP 核或 IP 模块,这些组件可以在设计芯片的过程中被集成到芯片中。…

Git代码冲突-不同分支之间的代码冲突

1、解决思路在团队开发中,提交代码到Git仓库时经常会遇到代码冲突的问题。- 原因:多人对相同的文件进行了编辑,造成代码存在差异化- 解决方案:1. 使用工具或git命令对比不同分支代码的差异化2. 把不同分支中有效代码进行保留&…

[译文] 基于PostGIS3.1 生成格网数据

根据格网进行数据统计与分析是一种常用的方法,相比自然地理边界与行政管理边界而言,使用格网有如下特点:每个格网之间地位相等,没有上下级之分。每个格网的面积都相等。相邻两个格网单元中心点之间距离相等。适用于将数据从“空间…

ThreeJS加载公路GeoJson数据实现流光效果

threejs加载公路geojson数据,跟加载行政区域的原理一样,唯一不同的是geojson格式不一样,路线并不是连贯起来的,按照路段进行的拆分,在加载的时候问题不大,正常解析然后转墨卡托投影,但是在做流光效果时,需要对geojson进行重新组合. 实现效果:

Android:反编译apk踩坑/apktool/dex2jar/JDGUI

需求描述 想要反编译apk文件,搜到了这篇博客:Android APK反编译就这么简单 详解(附图),非常有参考价值~但其中的工具下载链接都已404,而本杂鱼实际操作的过程中也出现了亿点点点点点点的问题,于…

电子技术——反馈对放大器极点的影响

电子技术——反馈对放大器极点的影响 放大器的频率响应和稳定性可以直接由其极点决定。因此我们将深入反馈对放大器极点的影响。 稳定性和极点位置 我们首先讨论稳定性和极点位置的关系。首先我们给出结论,对于任何一个稳定的放大器,其极点都处在 sss …

prometheus + alterManager + 飞书通知,实现服务宕机监控告警;实测可用

架构设计图 最终效果图 项目准备 xml依赖 <!-- 监控相关 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>io.…

Elasticsearch7.8.0版本进阶——段合并

目录一、段的概述1.1、段的概念1.2、段的缺点1.3、如何解决段数量暴增问题二、段合并的流程三、段合并的注意事项一、段的概述 1.1、段的概念 每一 段 本身都是一个倒排索引。 1.2、段的缺点 由于自动刷新流程每秒会创建一个新的段 &#xff0c;这样会导致短时间内的段数量…

interrupt多线程设计模式

1. 两阶段终止-interrupt Two Phase Termination 在一个线程T1中如何“优雅”终止线程T2&#xff1f;这里的【优雅】指的是给T2一个料理后事的机会。 错误思路 ● 使用线程对象的stop()方法停止线程&#xff08;强制杀死&#xff09; —— stop&#xff08;&#xff09;方法…

Linux内核的虚拟内存(MMU、页表结构)

前言&#xff1a;内存是程序得以运行的重要物质基础。如何在有限的内存空间运行较大的应用程序&#xff0c;曾是困扰人们的一个难题。为解决这个问题&#xff0c;人们设计了许多的方案&#xff0c;其中最成功的当属虚拟内存技术。Linux作为一个以通用为目的的现代大型操作系统&…

【git】Idea中git的使用

配置git 创建git仓库 不同颜色代表的含义 红色——未加入版本控制&#xff1b;绿色——已经加入控制暂未提交&#xff1b;蓝色——加入&#xff0c;已提交&#xff0c;有改动&#xff1b;白色——加入&#xff0c;已提交&#xff0c;无改动&#xff1b;灰色——版本控制已忽略文…

8、STM32 FSMC驱动LCD(ILI93xx)

本文使用FSMC驱动LCD显示&#xff0c;关于建议先看之前的7、STM32 FSMC驱动SRAM一文 硬件连接&#xff1a; 一、CubeMx配置FSMC驱动LCD ILI93xx 此章只为快速使用LCD&#xff0c;不涉及原理、指令说明 显示屏驱动文件参考正点探索者 1、CubeMx图形配置 此处的时序还可以调…

GLOG如何清理日志

1 日志清理 其实GLOG很长时间以来都没有日志清理功能。小白对此也很震惊&#xff0c;还特意去查了GLOG的提交记录。代码的提交记录显示&#xff0c;GLOG与日志清理有关的最初代码是2019年11月1日&#xff0c;而这个开源项目的起始时间可以追溯到2008年。也就是说&#xff0c;在…

浅谈liunx init.d 和 rc.local 两种起动方式

浅谈liunx init.d 和 rc.local 两种起动方式 以rabbitmq 举例 &#xff08;一&#xff09;.init.d 方式 开机自动重启设置 1.在/etc/init.d 目录下新建一个 rabbitmq [rootlocalhost init.d]# vi rabbitmq具体脚本如下所示&#xff1a; #!/bin/bash # # chkconfig: 2345 …

【离线数仓-7-数据仓库开发DIM层设计要点-拉链表同步装载脚本】

离线数仓-7-数据仓库开发DIM层设计要点-拉链表同步&装载脚本离线数仓-7-数据仓库开发DIM层设计要点-拉链表同步&装载脚本一、DIM层 维度模型 设计要点6.用户维度表 -拉链表1.用户维度表 前期梳理2.用户维度表 DDL表设计分析3.用户维度表 加载数据分析1.拉链表首日装载数…

RocketMQ 5.x新版本部署优化一览

​ RocketMQ从2022年9月份开始推出了新的5.x大版本。相比于之前的4.x版本&#xff0c;5.x版本向云原生前进了一大步。在增强原因功能的基础上&#xff0c;更是支持多语言客户端&#xff0c;周边生态也进行了补强和完善&#xff0c;明显可以看到离Kafka老大哥又近了很大一步。 …

linux网络编程-多进程实现TCP并发服务器

服务端流程步骤socket函数创建监听套接字lfdbind函数将监听套接字绑定ip和端口listen函数设置服务器为被动监听状态&#xff0c;同时创建一条未完成连接队列&#xff08;没走完tcp三次握手流程的连接&#xff09;&#xff0c;和一条已完成连接队列&#xff08;已完成tcp三次握手…

3-虚拟机篇

一.java JVM 的内存结构 内存&#xff1a;按线程类型分两类 线程共享&#xff1a; 方法区&#xff1a;存放类的信息堆&#xff1a;存放java对象的信息 线程私有&#xff1a; java虚拟机栈&#xff1a;存放java方法、方法参数和局部变量程序计数器&#xff1a;记录程序执行…

mars3d将当前视⻆指向北⽅且加载建筑物白膜

通过 setView⽅法实现&#xff0c;可以设置heading参数控制相对旋转⻆度map.scene.camera.setView({ orientation: { heading: 0, } }) 相关示例&#xff1a;1.http://mars3d.cn/editor-vue.html?idmap/options/scene2.功能示例(Vue版) | Mars3D三维可视化平台 | 火星科技// *…

ESP32S3 SPI发送间隔频率 驱动ADS8326

ESP32S3 SPI发送间隔频率驱动ADS8326esp32s3 spi例程 代码测试用寄存器方式实现spi发送寄存器描述驱动ADS8326 ads8326驱动时序 首先CS信号拉低&#xff0c;然后clk发送6个时钟&#xff0c;ads8326开始启动转换。 最后clk发送16个时钟&#xff0c;就会读取到两个字节的数据&a…