IO多路复用

2023-11-20

1. IO模型

IO模型是指四种不同的文件读写方式.

(1) 阻塞IO

阻塞IO是最常用,最简单,效率最低的一种IO模型.

  • 阻塞读

    如果有数据可读,则直接读取数据

    如果没有数据可读,则读会阻塞,直到读取到数据 或 出错才返回

  • 阻塞写

    如果有空间可供写入,则立即写入数据并返回

    如果空间已满在执行写入时,则写会阻塞,直到有空间 或 出错 才返回

(2) 非阻塞IO

可以防止进程或线程阻塞在IO操作上, 但是无法确保IO能够准确完成相应的操作.

  • 非阻塞读

    如果有数据可读,则直接读取数据并返回

    如果没有数据可读,也会立即返回 (0)

  • 非阻塞写

    如果有空间可供写入,则直接写入数据并返回

    如果没有空间可写,也会立即返回 (0)

    ==> 对于非阻塞IO来说,有时候为了能够读取/写入数据,可能需要进行轮询.

    例子 :

    ssize_t timedread(int fd,void * buf,int count ,int timeout)
    {
        while((ret == read(fd,buf,count) == 0)
        {
            usleep(1000);
            if(timeout-- <= 0)
            {
                break;
            }
        }
                
        return ret;
    }
    

    如何设置文件描述符 是 阻塞IO 还是 非阻塞IO ?

    ​ 阻塞IO 和 非阻塞IO 是由文件文件描述符的 O_NONBLOCK 标志来决定的

    ​ 如果在open时,flag参数中 位或 了 O_NONBLOCK 则文件描述符为非阻塞

    ​ 如果在open时, flag参数中没有O_NONBLOCK 的标志,则文件描述符默认(阻塞)

(3) 异步通知

在文件可读或可写的时候, 有驱动向系统发送一个SIGIO信号来提醒进行.

(4) IO多路复用

允许同时对多个阻塞IO进行控制操作

提前监视这些阻塞IO 是否 已经可读,可写或出错, 当条件满足后,再去执行相应的读写操作.

​ select poll epoll ==> 用来监视文件描述符的

2. select


       #include <sys/select.h>
    #include <sys/time.h>
    #include <sys/types.h>
       #include <unistd.h>
    
 			fd_set     : 文件描述符的集合. "类型"
                API函数接口 :
   							FD_SET(fd,fd_set);//把一个文件描述符fd加入到fd_set这个集合中去
   							FD_CLR(fd,fd_set);//把一个文件描述符fd从集合中fd_set中清掉
   							FD_ZERO(fd,fd_set);//把一个集合fd_set全部清掉
   							FD_ISSET(fd,fd_set);//判断文件描述符fd是否在fd_set这个集合中.
   
       int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
			nfds    : 一般填你感兴趣的最大文件描述符 +1
			readfds : 要监听读的文件描述符的集合;
			writefds: 要监听写的文件描述符的集合;
			exceptfds : 要监听出错的文件描述符的集合;
					在调用前,调用者要填入你 "你感兴趣的文件描述符"
                    在函数返回后,三个集合中,"是已经就绪的文件描述符"
                   

			timeoutv:  超时时间设置.
              struct timeval 
              {
                  long    tv_sec;         /* seconds */
                     long    tv_usec;        /* microseconds */
           		 };
				在调用前, 调用者要填入的是 "设定的超时时间"
             在函数返回后, 这个timeout指向的是剩余时间.
             返回值 :
   				> 0 :表示已经就绪的文件描述符的个数.
                   = 0 : 表示超时.
                   < 0 : 表示出错啦
                       

   			select的实现是在内核中开辟了一个内核线程去实现 :
   				同时监听的 . "轮询" : 轮流询问
                while(不超时)
                {
                    先问一遍 [0 , 你感兴趣的文件描述符最大的那个)
                        //[0,nfds)
                    if(有文件就绪)
                    {
                        break;
                    }
                    
                    sleep t;
                }
			
		void FD_CLR(int fd, fd_set *set);
       	int  FD_ISSET(int fd, fd_set *set);
       	void FD_SET(int fd, fd_set *set);
       	void FD_ZERO(fd_set *set);
	

例子 :

  1. select 延时的效果
struct timeval timeout;
 timeout.tv_sec = 5;
tiemtout.tv_usec = 0;
  
select(100,NULL,NULL,NULL,&timeout);
   <==> sleep(5);
    <==> usleep();

3.poll

pool的功能和select类似, “监听多个文件描述符 , 是否就绪”.

只不过poll用一个结构体 struct poolfd 来描述 , ‘‘监听请求’’


       #include <poll.h>   
        struct pollfd 
        {
               int   fd;         //指定要监听的文件描述符
               short events;     //监听的事件
               						在linux内核中, 事件用bit-fields
               						POLLIN  : 可读的事件
                                         POLLOUT : 可写的事件
                                         POLLERR : 出错的事件
                                           ...: 
               						 POLLIN | POLLOUT
               short revents;    //已经就绪的事件: 是否已经可读
                                    if(revents & POLLIN)
                                    {
                                        可读的
                                    }   						
           };
   
   			监听一个文件描述符, 就需要一个 struct pollfd 的结构体
            监听多个文件描述符, 就需要多个 struct pollfd 的结构体
            ....


       int poll(struct pollfd *fds, nfds_t nfds, int timeout);
   			fds : 监听结构体 struct pollfd 的数组
         nfds :表示第一个参数 struct pollfd数组的元素个数
         timeout : 超时时间.单位 ms
            返回值 :
				> 0 表示就绪的文件个数
                   = 0 表示超时
                   < 0 出错啦
   

4.epoll : man epoll

(1) epoll_create : 创建一个监听文件的集合,这个函数的返回值是一个文件描述符

NAME
       epoll_create - open an epoll file descriptor

SYNOPSIS
       #include <sys/epoll.h>

       int epoll_create(int size);
			size : 已经被忽略了. 但是 > 0
            返回值 :
				成功 返回一个epoll的实例(对象),就是一个文件描述符
                失败 返回-1,同时errno被设置

创建一个epoll的实例, 用来监听多个其他的文件描述符

那么要监听的文件描述符, 如何加入这个监听的实例中去呢?

(2) epoll_ctl


       #include <sys/epoll.h>

    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
   			epfd : epoll监听集合的文件描述符, epoll_create 返回值
         op : 具体是何种操作, 常用的有如下 :
   				EPOLL_CTL_ADD :
					增加. 把一个要监听的文件描述符及监听事件
                    加入到epoll实例中去.
             EPOLL_CTL_DEL :
					从监听集合中删除一个文件描述符.
                EPOLL_CTL_MOD : modify
                    修改个月已经在监听集合中的文件描述符的监听事件.
         fd : 要监听或删除或修改的 文件描述符
            event : 要监听的事件的结构体的指针.
                在epoll中,用一个结构体 struct epoll_event
                    来描述一个要监听的事件.
                struct epoll_event 
                {
                    uint32_t     events;     
                    				要监听的事件标志, bit-fields
                                    可用的监听事件有如下 :
                    				    EPOLLIN    :可读的事件
                                        EPOOLOUT    : 可写的事件
                                        EPOLLRDHUP  : 这个事件 用来监听 流式套接字(tcp sockfd)
                                            对方是否已经关闭或关闭写
                                        RPOLLERR : 出错事件
                                        ...
                                  EPOLLET : Edge-Triggered 边缘触发
                                  LT : Level-Triggered
                                                只要有数据,就会不同的上报可读事件
                                                	EPOLLIN
                                                默认行为 : LT
                                   ET : Edge-Triggered
                                                有数据变化(数量),才报告可读事件
                                                
                                            例子 :
                    							一个文件里面有 2K数据
                                                  报告可读的事件.
                                                这个时候, 你读走了1K数据,文件剩余1K.
                                                    
                                                  LT : ---> 不停地上报可读事件
                                                  
                                                  ET : ----> 在数据有变化的情况下才会上报.
                    				
                    epoll_data_t data;        /* User data variable */
                    			//用来保存用户的一些数据
           	    };
   
   				typedef union epoll_data 
                {
                 void        *ptr;//用户的数据指针
                 int          fd;//文件描述符
                    uint32_t     u32;//
                    uint64_t     u64;//
           		} epoll_data_t;
   
   				返回值 :
   					成功 返回 0
                 失败 返回-1,同时errno被设置;

(3) epoll_wait : 用来等待监听事件的发生

NAME
       epoll_wait - wait for an I/O event on an epoll file descriptor

SYNOPSIS
       #include <sys/epoll.h>

       int epoll_wait(int epfd, struct epoll_event *events,
                      int maxevents, int timeout);
			 epfd : epoll实例
             events :结构体数据,用来保存已经就绪事件的信息的.
             maxevents : 表示第二个参数结构体数组最多可以保存多少个事件结构体.
             timeout :超时时间 , 单位 为 ms
             返回值 :
				> 0 已经就绪的文件描述符的个数
                = 0 表示超时了
                = -1 出错了

总结 :

  1. select 实现原理

    select函数在调用时,会从文件描述符 0 - nfds - 1 依次轮询遍历这些文件描述符在 readfds,writefds,exceptfds这是三个集合中存在是否就绪,如果没有就绪,则会在timeout指定的超时时间内一直循环遍历, 如果有就绪的,则在在当次轮询完会立即返回.

  2. poll实现原理

    poll是通过struct pollfd结构体数组的形式来指定并感兴趣的文件描述符是否就绪,该结构体中的 events成员用来指定感兴趣的事件,revents是用来存放以及就绪的事件,poll是通过指定的时间内,不断的去询问fds中的指定的文件描述符是否就绪

    ===> 单次轮询次数为nfds ,比select少

  3. epoll实现原理

    epoll是以对象的形式来描述一些你感兴趣点额文件描述符

    ==> epoll对象(感兴趣的文件描述符对象)

    epoll支持文件描述符数量很多的情况下,效率要比select/poll

    epoll支持 ET

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

IO多路复用 的相关文章

  • 在阿里云ECS云服务器上部署和使用开源的应用程序容器引擎Docker

    Docker 是一个开源的应用程序容器引擎 具有可移植性 可扩展性 高安全性和可管理性等优势 它允许开发人员将应用程序和依赖项打包到可移植容器中 从而在 Linux 机器上高效构建 部署和管理应用程序 阿里云提供Docker镜像仓库 用于快
  • 一个网工(网络工程师)七年的职业血泪史....

    前言 一个工作了七年的老网工 上家公司待了五年 现在这家公司也快三年了 分享一些我自己学习网络安全路上的一些经历 也算是帮大家少走些弯路 一 如何学习网络安全 1 不要试图以编程为基础去学习网络安全 不要以编程为基础再开始学习网络安全 一般
  • 广告竞价策略:激发广告变现潜能的关键

    在数字化时代 广告已经成为企业推广品牌 产品和服务的关键手段之一 为了最大程度地发挥广告的效果 广告竞价策略成为广告主和数字营销专业人士关注的焦点 通过巧妙运用竞价策略 广告主可以在激烈的市场竞争中脱颖而出 实现广告变现的潜能 admaoy
  • 网络基础面试题(二)

    11 什么是网桥 防火墙的端口防护是指什么 网桥是一种网络设备 用于连接两个或多个局域网 LAN 并转发数据包 它能够根据MAC地址来识别和转发数据 提高网络的传输效率和安全性 防火墙的端口防护是指对防火墙上的各个端口进行保护和限制 只允许
  • 如何使用内网穿透实现iStoreOS软路由公网远程访问局域网电脑桌面

    文章目录 简介 一 配置远程桌面公网地址 二 家中使用永久固定地址 访问公司电脑 具体操作方法是 简介 软路由 是PC的硬件加上路由系统来实现路由器
  • 【一份老网工珍藏多年的网络配置笔记,很重要!】

    01 交换机 路由器的几种配置模式及模式转换 1 用户模式 登录到交换机 路由器 时会自动进入用户模式 提示符为 switchname gt 在该模式下只能够查看相关信息 对 IOS的运行不产生任何影响 2 特权模式 用户模式下 键入 en
  • 浅谈能耗系统在马来西亚连锁餐饮业的应用

    1 背景信息 Background 针对连锁餐饮业能耗高且能源管理不合理的问题 利用计算机网络技术 通讯技术 计量控制技术等信息化技术 实现能源资源分类分项计量和能源资源运行监管功能 清晰描述各分店总的用能现状 实时监测各供电回路的电压 电
  • CTF之逆向入门

    逆向工程 Reverse Engineering 又称反向工程 是一种技术过程 即对一项目标产品进行逆向分析及研究 从而演绎并得出该产品的处理流程 组织结构 功能性能规格等设计要素 以制作出功能相近 但又不完全一样的产品 逆向工程源于商业及
  • nohup - 后台执行

    nohup no hang up 语法 nohup Command Arg 使用示例 nohup python a py 日志将被保留在 当前文件夹下的 nohup out 将日志放到文件 不输出到终端 echo hello gt 1 tx
  • 服务器集群是如何提高计算性能的?

    服务器集群是一种将多台服务器连接起来协同工作的技术 通过集群配置 可以提高计算性能 可靠性和可扩展性 以下是服务器集群如何提高计算性能的详细解释 一 并行处理能力 服务器集群的核心优势在于其并行处理能力 通过将多个服务器组成一个集群 可以将
  • centos系统有什么好处?

    CentOS是一种基于开源代码的Linux操作系统 它有以下几个优势 1 稳定性 CentOS是一种非常稳定的操作系统 它的代码经过了严格的测试和审查 因此它非常适合作为服务器操作系统使 用 2 安全性 由于CentOS是基于开源代码的操作
  • Web 安全漏洞之 OS 命令注入

    什么是 OS 命令注入 上周我们分享了一篇 Web 安全漏洞之 SQL 注入 其原理简单来说就是因为 SQL 是一种结构化字符串语言 攻击者利用可以随意构造语句的漏洞构造了开发者意料之外的语句 而今天要讲的 OS 命令注入其实原理和 SQL
  • 38条Web测试经验分享

    1 页面链接检查 每一个链接是否都有对应的页面 并且页面之间切换正确 可以使用一些工具 如LinkBotPro File AIDCS HTML Link Validater Xenu等工具 LinkBotPro不支持中文 中文字符显示为乱码
  • 线程安全(中)--彻底搞懂synchronized(从偏向锁到重量级锁)

    接触过线程安全的同学想必都使用过synchronized这个关键字 在java同步代码快中 synchronized的使用方式无非有两个 通过对一个对象进行加锁来实现同步 如下面代码 synchronized lockObject 代码 对
  • WEB前端常见受攻击方式及解决办法总结

    一个网址建立后 如果不注意安全问题 就很容易被人攻击 下面讨论一下集中漏洞情况和放置攻击的方法 一 SQL注入 所谓的SQL注入 就是通过把SQL命令插入到web表单提交或输入域名或页面请求的查询字符串 最终达到欺骗服务器执行恶意的SQL命
  • 用户数据中的幸存者偏差

    幸存者偏差 Survivorship bias 是一种常见的逻辑谬误 意思是没有考虑到筛选的过程 忽略了被筛选掉的关键信息 只看到经过筛选后而产生的结果 先讲个故事 二战时 无奈德国空防强大 盟军战机损毁严重 于是军方便找来科学家统计飞机受
  • 2024年金三银四网络安全考试试题

    2023年金三银四网络安全考试试题 1 关于数据使用说法错误的是 A 在知识分享 案例中如涉及客户网络数据 应取敏感化 不得直接使用 B 在公开场合 公共媒体等谈论 传播或发布客户网络中的数据 需获得客户书面授权或取敏感化 公开渠道获得的除
  • Jmeter 性能-并发量计算

    并发概念 指网站在同一时间访问的人数 人数越大瞬间带宽要求更高 服务器并发量分为 业务并发用户数 最大并发访问数 系统用户数 同时在线用户数 估算业务并发量的公式 C nL T C C 3 C的平方根 说明 C是平均的业务并发用户数 n是l
  • 服务器VPS是什么意思?一文了解其含义与重要性

    在今天的数字时代 服务器扮演着至关重要的角色 它们是网站 应用程序和在线业务的基石 但是 你是否听说过VPS 本文将深入探讨什么是服务器VPS 以及为什么它在今天的互联网世界中如此重要 什么是服务器VPS 服务器的基本概念 在我们深入探讨V
  • 静态综合实验

    1 IP地址划分 192 168 1 0 27 用于主干拆分 192 168 1 32 27 用于用户拆分 192 168 1 64 27 用于用户拆分 192 168 1 96 27 用于用户拆分 192 168 1 128 27 用于用

随机推荐

  • 区块链数据的存储和更新

    目录 1 引言 2 主要流程 2 1数据库读取 2 1 1 从数据库加载块数据 2 1 2从数据库读取账户信息 2 2 区块链数据更新与回滚 2 2 1 交易数据 2 2 2 块数据 1 引言 在第一篇文章里我们从静态的角度讲解了以太坊的数
  • elasticsearch ES搜索权重设置(boost参数)

    摘要 7 Elasticsearch boost的搜索条件权重 lm324114的专栏 CSDN博客 boost es 摘要2 elasticsearch boost 简书 摘要3 Elasticsearch 10 Boost 提升权重 简
  • flutter ListView 滚动到最后一个items位置

    flutter 想要实现一个listview初始化时和数据变化后显示到列表的最末 简单地说就是像聊天窗或者是日志输出那样的情景 要在Flutter中实现在初始化时和数据变化后将ListView自动定位到最后一个item的位置 你可以使用Sc
  • 基于位置的 AR 应用程序开发最完整指南

    几年前 全世界都为 Pokemon Go 疯狂 虽然这款游戏令人难以置信的受欢迎程度正在缓慢下降 但增强现实已成为科技界的新趋势 并且正在自信地抢占市场份额 2020年 AR市场规模超过141亿美元 预计到2022年底将达到2092亿美元
  • 混合式A星代码解析_2 规划主程序Planner.cpp

    3 规划程序 Planner cpp 在main cpp中 起主要作用的就是 HybridAStar Planner hy hy plan 规划算法都是在HybridAStar Planner这个类内部进行运算的 所以主要分析以下Plann
  • 客户端html跳到cas登出页面,CAS单点登录:单点登出及自定义登出界面(六)

    1 单点登出 1 1 参数说明 配置单点登出 配置允许登出后跳转到指定页面 cas logout followServiceRedirects false 跳转到指定页面需要的参数名为 service cas logout redirect
  • 扫描二维码进入体验版小程序却一直进入线上版本?这个配置要注意!

    1 前期准备 服务器 域名 2 配置扫描普通二维码进入小程序页面 开发小程序过程中 我们会遇到很多不同的场景 其中 扫描普通二维码进入小程序就是其中之一 下面先来看下如何配置扫描普通二维码进入小程序 首先登录开发平台 打开开发管理 进入开发
  • 大端小端,LSB和MSB

    在verilog中碰到了lsb和msb 所以做一下解释 lsb 就是最低位有效 类似于wire 0 31 这样的顺序 msb 就是最高位有效 类似于wire 31 0 这样的顺序 还有计算机中还有大端小端的概念一块解释一下 举例 0X123
  • 2022/9/6小结

    成长 是一个探索自我的过程 看 了不起的我 这本书 不知道是那句话 那个段落 或者那一章触动到了我 曾经我无法发自内心地去读书 去感受书中的情感 或悲伤 或喜悦 曾经我迫切地想通过书籍获得一项技能 获得一种读书人的气质 很幼稚 我不是在读书
  • Linux绑核效率优化

    Linux绑核效率优化 原理概述 cpu一般有多个物理核心 但在运行进程和线程时候 可以将其绑定或者指定到某一个或者多个核心上运行 这样做的好处是 一般在核数比较多的机器上 会有多个CPU共享三级缓存cache的情况 当出现跨cache数据
  • electron创建新窗口(模态框)并相互传值,主进程传值给子进程

    我们在开发的过程中难免会遇到需要创建一个子窗口 子进程 但是在这个子进程中所有值都是初始化的 而我们肯定是需要一些值才能进行下一步操作 比如 token 那么我们怎么去传递值呢 我先给伙伴们说一些 基本原理 下面很多东西会建立在vue的基础
  • line-height: 1

    价格文字 问题 新价格 旧价格 每个都设置了自己的line height 结果就是 新价格 旧价格 的底部没有与父元素 div 贴底 样式调试起来很难 解决办法 新价格 旧价格 的 line height 都设置为 1 成功
  • chrony配置服务器时间同步

    chrony 设置时区 timedatectl set timezone Asia Shanghai 查看时区 timedatectl date R 设置时间 date s 20211109 11 32 30 时区和时间配置好之后 配置ch
  • STM32--IIC

    1 IIC总线协议介绍 IIC Inter Integrated Circuit 集成电路总线 是一种同步串行半双工通信总线 IIC总线结构图 由时钟线SCL和数据线SDA组成 并且都接上拉电阻 确保总线空闲状态为高电平 总线支持多设备连接
  • antd + react model自定义footer_阿里开源可插拔的企业级React应用框架——UmiJS

    介绍 UmiJS 五米 是阿里开源的可插拔企业级React应用框架 为什么说是可插拔 是因为它的整个生命周期都是插件化的其内部也有很多都是通过插件来实现的 其中大家熟知的Ant Design pro就是基于umi构建的 官方文档 中文文档
  • Zabbix安装部署(国内源镜像)----一次性解决centos7安装zabbix报错:[Errno 256] 的问题

    Zabbix安装部署 环境准备 OS CentOS 7 安装步骤 一 关闭selinux和iptables root localhost systemctl stop firewalld service root localhost set
  • 相关性分析p值_相关性分析的结果解读及说明

    下图是三个不同的变量 Y 分别与变量X的相关性分析结果 1 相关系数r r 1 二者具有完美的正相关 r 0到1之间 两个变量一起增加或者一起减少 r 0 二者没有相关性 r 1到0 一个变量随着另一个变量的增加而减少 或者减少而增加 r
  • Feign客户端 - 超时时间配置

    Spring Cloud 专栏收录该内容 7 篇文章0 订阅 订阅专栏 Spring Cloud中Feign客户端是默认开启支持Ribbon的 最重要的两个超时就是连接超时ConnectTimeout和读超时ReadTimeout 在默认情
  • vue3前端以json样式输入组件实现

    在 Vue 3 中 你可以创建一个组件 让用户输入 JSON 并将这个 JSON 渲染成某种样式或结构 以下是一个简单示例 它涵盖了如何在 Vue 3 中创建一个接受 JSON 输入并呈现其内容的组件 Setup Vue Project 如
  • IO多路复用

    1 IO模型 IO模型是指四种不同的文件读写方式 1 阻塞IO 阻塞IO是最常用 最简单 效率最低的一种IO模型 阻塞读 如果有数据可读 则直接读取数据 如果没有数据可读 则读会阻塞 直到读取到数据 或 出错才返回 阻塞写 如果有空间可供写