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…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...

Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
uniapp 实现腾讯云IM群文件上传下载功能
UniApp 集成腾讯云IM实现群文件上传下载功能全攻略 一、功能背景与技术选型 在团队协作场景中,群文件共享是核心需求之一。本文将介绍如何基于腾讯云IMCOS,在uniapp中实现: 群内文件上传/下载文件元数据管理下载进度追踪跨平台文件预览 二…...

Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...

C++_哈希表
本篇文章是对C学习的哈希表部分的学习分享 相信一定会对你有所帮助~ 那咱们废话不多说,直接开始吧! 一、基础概念 1. 哈希核心思想: 哈希函数的作用:通过此函数建立一个Key与存储位置之间的映射关系。理想目标:实现…...