Linux I/O 多路复用机制详解
文章目录
- 1 文件描述符(File Descriptor)
- 1.1 什么是文件描述符?
- 1.2 文件描述符与文件的关系
- 2 文件描述符集合(File Descriptor Set)
- 2.1 什么是文件描述符集合?
- 2.2 `fd_set` 结构体
- 3 `select()` 函数的工作原理
- 3.1 `select()` 函数概述
- 3.2 `select()` 的工作步骤
- 4 `poll()` 函数的工作原理
- 4.1 `poll()` 函数概述
- 4.2 `pollfd` 结构体
- 4.3 `poll()` 的工作步骤
- 5 `select()` 和 `poll()` 的底层比较
- 6 总结
- 参考链接
- 封面
本文将详细解释文件描述符、文件描述符集合,以及
select()
和
poll()
的底层工作原理,以帮助理解 Linux 系统的 I/O 多路复用机制。
1 文件描述符(File Descriptor)
1.1 什么是文件描述符?
在 Unix 和 Linux 系统中,文件描述符(File Descriptor, FD) 是一个非负整数,用于表示已打开的文件、网络套接字、管道等 I/O 资源。每个进程都有一个文件描述符表,这个表记录了进程当前打开的所有文件。
1.2 文件描述符与文件的关系
当一个进程打开一个文件(或其他 I/O 资源),内核会为这个文件分配一个文件描述符,并将其返回给进程。这个文件描述符可以用来标识和访问该文件。例如:
int fd = open("example.txt", O_RDWR);
在这段代码中,open()
函数返回的 fd
就是文件描述符,它指向已打开的 example.txt
文件。之后,进程可以使用 fd
来读取或写入文件。
2 文件描述符集合(File Descriptor Set)
2.1 什么是文件描述符集合?
文件描述符集合 是一组文件描述符的集合,通常用于 I/O 多路复用函数 select()
中。它们用来表示一组文件描述符的状态(如可读、可写或有错误)。在 Linux 中,文件描述符集合通常由 fd_set
结构体表示。
2.2 fd_set
结构体
fd_set
是一个位图,每个比特位对应一个文件描述符。如果集合中包含某个文件描述符,则该比特位被设置为 1,否则为 0。以下是常用的操作:
- FD_ZERO:清空集合(将所有比特位设置为 0)。
- FD_SET:将一个文件描述符加入集合(将对应比特位设置为 1)。
- FD_CLR:从集合中移除一个文件描述符(将对应比特位设置为 0)。
- FD_ISSET:检查某个文件描述符是否在集合中(检查对应比特位是否为 1)。
3 select()
函数的工作原理
3.1 select()
函数概述
select()
是一种 I/O 多路复用技术,用于同时监视多个文件描述符的状态(如可读、可写或有错误),并在其中一个或多个文件描述符的状态发生变化时返回。select()
的函数签名如下:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
3.2 select()
的工作步骤
-
初始化文件描述符集合:
- 使用
FD_ZERO
清空集合,然后用FD_SET
将感兴趣的文件描述符加入集合。
- 使用
-
调用
select()
:- 内核将挂起进程,并同时监控
readfds
、writefds
和exceptfds
中的文件描述符,直到其中一个或多个文件描述符的状态发生变化,或者超时。
- 内核将挂起进程,并同时监控
-
内核检查文件描述符状态:
- 内核会遍历所有文件描述符,检查它们的状态。如果一个文件描述符变得可读、可写或发生异常,内核会设置相应集合中的比特位。
-
select()
返回并处理结果:select()
返回文件描述符集合的状态。应用程序可以使用FD_ISSET
检查哪些文件描述符已经准备好进行 I/O 操作。
4 poll()
函数的工作原理
4.1 poll()
函数概述
poll()
是另一种 I/O 多路复用技术,与 select()
类似,但它使用不同的方式来表示文件描述符集合。poll()
的函数签名如下:
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
4.2 pollfd
结构体
pollfd
结构体包含了一个文件描述符及其感兴趣的事件和返回的状态:
struct pollfd {int fd; /* 监视的文件描述符 */short events; /* 感兴趣的事件 */short revents; /* 返回的事件 */
};
4.3 poll()
的工作步骤
-
初始化
pollfd
结构体数组:- 填充
pollfd
结构体数组,指定每个文件描述符和感兴趣的事件。
- 填充
-
调用
poll()
:- 内核将挂起进程,并监视
fds
数组中所有文件描述符的状态,直到某个文件描述符的状态发生变化,或者超时。
- 内核将挂起进程,并监视
-
内核检查文件描述符状态:
- 内核逐个检查
fds
数组中的文件描述符,并更新revents
字段,表示实际发生的事件。
- 内核逐个检查
-
poll()
返回并处理结果:poll()
返回后,应用程序检查revents
字段,确定哪些文件描述符已经准备好进行 I/O 操作。
5 select()
和 poll()
的底层比较
-
效率:
select()
使用位图来表示文件描述符集合,这意味着它最多只能监视FD_SETSIZE
(通常是 1024)个文件描述符。同时,由于每次调用select()
都需要重新设置位图集合,因此在处理大量文件描述符时效率较低。poll()
使用数组来表示文件描述符集合,理论上可以监视任意数量的文件描述符。而且poll()
不需要每次重置整个数组,只需更新感兴趣的事件即可,因此效率更高。
-
灵活性:
poll()
提供了对更多事件类型的支持(如POLLPRI
,表示高优先级数据),而select()
只支持基本的可读、可写和异常事件。
-
扩展性:
select()
的文件描述符数量受限于FD_SETSIZE
,而poll()
没有这个限制,因此在需要处理大量文件描述符的场景,poll()
更具扩展性。
6 总结
- 文件描述符 是进程与文件或其他 I/O 资源交互的句柄,每个进程都有自己的一组文件描述符。
- 文件描述符集合 是多个文件描述符的集合,通常用于
select()
函数中,以同时监视多个文件描述符的状态。 select()
通过使用位图集合来监视多个文件描述符的状态,适合处理小数量的文件描述符。poll()
通过使用数组来监视多个文件描述符的状态,适合处理大量文件描述符,且效率更高。
无论是 select()
还是 poll()
,它们的核心作用都是提供一种机制来同时监视多个文件描述符的状态,并在这些文件描述符的状态发生变化时通知应用程序,从而实现高效的 I/O 多路复用。
参考链接
- Linux man page for select
- Linux man page for poll
封面
由 DALL-E-3 生成
相关文章:

Linux I/O 多路复用机制详解
文章目录 1 文件描述符(File Descriptor)1.1 什么是文件描述符?1.2 文件描述符与文件的关系 2 文件描述符集合(File Descriptor Set)2.1 什么是文件描述符集合?2.2 fd_set 结构体 3 select() 函数的工作原理…...

第43课 Scratch入门篇:雪花随风飘
雪花随风飘 故事背景: 雪花轻轻地从灰蒙蒙的天空中飘落下来,它们像是天空中飘洒下来的羽毛,又像是冬日的精灵在翩翩起舞。每一片雪花都独一无二,它们在空中旋转、飘荡,最终缓缓降落在屋顶、树枝、街道和行人的肩头。 程序原理: 众多的雪花肯定是克隆功能,降落过程是通过…...

VueUse 基于 Vue 3 Composition API 的高质量 Hooks 库
VueUse 是什么? VueUse 是基于 Vue 3 Composition API 的高质量 Hooks 库。例如获取滚动的距离 VueUse 官网:VueUse | VueUse VueUse 什么使用? 1、通过npm安装 VueUse npm i @vueuse/core 2、搜索需要使用的函数,例如搜索 useScroll 滚动 3、使用useScroll 滚动函数 …...
ARM CoreLink 系列 5.1.1 -- CI-700 System Address Map 】
文章目录 System Address MapRN SAMRN SAM memory regions and target typesSAM memory region size configurationRN SAM target ID selectionSystem Address Map 所有的CHI 命令都包含一个 Source ID 和 Target ID, 其中 Source ID 可以来自于 RN Node, Target ID 可以来自…...
【数据结构】二叉树(一)
目录 1. 树型结构 概念 树的表示形式 编辑 2. 二叉树(重点) 2.1 概念 2.2 二叉树的性质 2.3 二叉树的存储 2.4 二叉树的遍历 前中后序遍历 层序遍历: 2.5二叉树的基本操作 本篇主要理解树和二叉树相关概念,二叉树遍…...
使用duplicate搭建备库或者级联备库
使用duplicate搭建备库或者级联备库: 主库或者源端: 1. 创建pfile,更改&添加部分参数、传输到备库; 2. 主库(或者源端)的tnsnames.ora文件添加 备库的连接信息 备库: 1. 备库添加静态监听 2…...

【存储学习笔记】4:快照(Snapshot)技术的实现方式
1 快照 1.1 动机 在上一篇《备份》里提到,热备份就是在执行操作时,服务器需要正常处理来自用户或应用对数据的更新,这样能够保证数据7*24小时可用(在很多服务里这是必要的)。 而热备份的困难就是如何保证数据的一致…...
数根(字符串数根公式)
公式:a的数根(a-1)%91; #include <bits/stdc.h> using namespace std; string s; long long sum; int main(){cin>>s;for(int i0;i<s.size();i){sums[i]-0;}cout<<(sum-1)%91; }...

C语言之文件操作上卷(二十一)(逆行人生-2024)
📣📣📣📣📣📣📣📣 ✏️作者主页:枫霜剑客 📋 系列专栏:C语言知识学习归纳总结(逐梦篇专栏合集) 🌲上一篇: C语…...
【微服务架构实战】结合实际案例进行微服务架构的设计与实现
微服务架构实战 结合实际案例进行微服务架构的设计与实现 引言 微服务架构(Microservices Architecture)是一种将大型应用程序拆分成一组小型、独立的服务的方法,每个服务都专注于特定的业务功能,并能够独立开发、部署和扩展。这…...
为什么要有二级指针
提示:文章 文章目录 前言一、背景二、 2.1 2.2 总结 前言 前期疑问: 本文目标: 一、背景 之前一直疑问为什么要有二级指针,一直没有写这个帖子,今天整理了一下,收获颇丰 二、 2.1 // 增加对二级指针…...

如何保证数据不丢失?(死信队列)
死信队列 1、什么是死信 死信通常是消息在特定的场景下表现: 消息被拒绝访问消费者发生异常,超过重试次数消息的Expiration过期时长或者队列TTL过期时间消息队列到达最大容量 maxLength 2、什么是死信队列 只由死信构成的消息队列是死信队列 死信队…...

树莓派开发笔记01-树莓派的系统烧录以及初次开机配置
github主页:https://github.com/snqx-lqh gitee主页:https://gitee.com/snqx-lqh 本项目github地址:https://github.com/snqx-lqh/RaspberryPiLearningNotes 本项目gitee地址:https://gitee.com/snqx-lqh/RaspberryPiLearningNote…...

微信答题小程序产品研发-后端开发
在开发答题小程序的后端服务和数据库设计时,需要考虑API的设计、数据库模型的构建以及数据的安全性和一致性。 这里我采用了云开发,后端语言是Node,数据库是NoSql,然后我简单整理了各个功能模块的后端开发概要和数据库设计。 1. …...
回溯算法——LeetCode37 解数独
题目 力扣题目链接 思路 卡哥的思路,注意看他解释为什么是“二维回溯”。我的思路,类似y总解决 N 皇后问题时的第二种方法,即从左上到右下枚举棋盘的每个位置。 至于为什么与 N 皇后问题不一样,我认为是因为它每一行不止放一个…...

【CPP】继承语法详解与菱形继承
关于我: 睡觉待开机:个人主页 个人专栏: 《优选算法》《C语言》《CPP》 生活的理想,就是为了理想的生活! 作者留言 PDF版免费提供:倘若有需要,想拿我写的博客进行学习和交流,可以私信我将免费提供PDF版。…...

数据结构(6.2_1)——领接矩阵法
图的存储——邻接矩阵法 邻接矩阵(Adjacency Matrix)是一种使用二维数组来表示图的方法。在这种表示法中,矩阵的行和列都对应图的顶点。 特点 对于无向图,如果顶点i与顶点j之间有边,则矩阵的第i行第j列(…...

诈骗未成功是否构成犯罪?
诈骗未成功不一定构成犯罪。在刑法上,构成诈骗罪需要满足特定的构成要件,包括有非法占有的目的、实施了虚构事实或隐瞒真相的行为、对方因此陷入错误认识并处分财产、行为人或第三方取得财产、被害人遭受财产损失。如果诈骗行为未能成功,即被…...

网络协议栈应用层的意义(内含思维导图和解析图通俗易懂超易理解)
绪论: “节省时间的方法就是全力以赴的将所要做的事情完美快速的做完,不留返工重新学习的时间,才能省下时间给其他你认为重要的东西。” 本章主要讲到OSI网络协议栈中的应用层的作用和再次在应用层的角度理解协议的具体意义,以及…...

【NXP-MCXA153】i2c驱动移植
介绍 I2C总线由飞利浦公司开发,是一种串行单工通信总线,它主要用于连接微控制器和其他外围设备并在总线上的器件之间传送信息(需要指定设备地址);常见的i2c设备有EEPROM、触摸屏、各种IoT传感器、时钟模块等&#x…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...