Linux——高级IO(select后续poll,epoll)

目录

一、poll函数

1.函数原型

2.参数说明

3.struct pollfd 结构体

4.返回值

5.使用步骤

6.与 select 的对比

7.适用场景

8.缺点

9.总结

二、epoll函数

1.核心思想

2.核心函数

1. epoll_create - 创建 epoll 实例

2. epoll_ctl - 管理 epoll 事件表

3. epoll_wait - 等待事件发生

3.事件类型

4.触发模式

1. 水平触发(LT,默认)

2. 边缘触发(ET)

5.使用步骤

6.示例代码(LT 模式)

7.优点

8.缺点

9.适用场景

10.对比 select/poll

11.注意事项

12.总结

三、当网卡接收到数据流程

1. 网卡接收数据(硬件层)

2. epoll 的事件触发(内核层)

关键数据结构

事件触发流程

3. 用户层获取事件(应用层)

流程总结(结合数据结构)

性能优势的根源

触发模式的影响

1. 水平触发(LT)

2. 边缘触发(ET)

完整流程示例

总结


一、poll函数

1.函数原型

#include <poll.h>int poll(struct pollfd *fds, nfds_t nfds, int timeout);

2.参数说明

  1. fds
    指向 struct pollfd 结构体数组的指针,每个结构体描述一个要监视的文件描述符及其关注的事件。

  2. nfds
    数组 fds 的长度(即监视的文件描述符数量)。

  3. timeout
    超时时间(毫秒):

    • -1: 阻塞等待,直到某个文件描述符就绪。

    • 0: 立即返回,不阻塞。

    • >0: 最多等待指定毫秒数。


3.struct pollfd 结构体

struct pollfd {int   fd;         // 监视的文件描述符short events;     // 关注的事件(输入)short revents;    // 实际发生的事件(输出)
};
  • events:应用程序关注的事件(按位或组合):

    • POLLIN:数据可读。
    • POLLOUT:数据可写。

    • POLLERR:发生错误。

    • POLLHUP:连接挂起(如对端关闭)。

    • POLLNVAL:文件描述符未打开。

  • revents:内核返回的实际事件,可能包含 events 中的事件或错误标志(如 POLLERR)。


4.返回值

  • >0:就绪的文件描述符数量。

  • 0:超时且没有文件描述符就绪。

  • -1:发生错误,可通过 errno 获取原因(如 EINTR 表示被信号中断)。


5.使用步骤

  1. 初始化 struct pollfd 数组,设置要监视的 fd 和 events

  2. 调用 poll,阻塞等待事件发生。

  3. 检查返回的 revents,处理就绪的文件描述符。

示例代码

struct pollfd fds[2];
fds[0].fd = sock_fd;      // 监视套接字
fds[0].events = POLLIN;   // 关注可读事件
fds[1].fd = pipe_fd;      // 监视管道
fds[1].events = POLLOUT;  // 关注可写事件int ret = poll(fds, 2, 1000);  // 等待1秒
if (ret > 0) {if (fds[0].revents & POLLIN) {// 套接字可读,处理数据}if (fds[1].revents & POLLOUT) {// 管道可写,发送数据}
}

6.与 select 的对比

  1. 文件描述符数量限制

    • select 使用固定大小的 fd_set,受 FD_SETSIZE 限制(通常 1024)。

    • poll 使用动态数组,理论上无限制。

  2. 效率

    • select 每次调用需重新传入所有文件描述符。

    • poll 通过分离 events 和 revents 字段,避免重复初始化。

  3. 可移植性

    • select 在所有系统可用。

    • poll 在部分旧系统(如早期 Windows)不支持。


7.适用场景

  • 需要监视的文件描述符数量较多(超过 FD_SETSIZE)。

  • 希望避免 select 的重复初始化开销。

  • 对跨平台兼容性要求不高。


8.缺点

  • 当监视大量文件描述符时,遍历所有 struct pollfd 检查 revents 效率较低(此时 epoll 或 kqueue 更高效)。


9.总结

poll 解决了 select 的部分缺陷,适合中等规模的高效 I/O 多路复用。在 Linux 上处理海量连接时,更推荐使用 epoll;而在 macOS/BSD 上,kqueue 是更优的选择。

二、epoll函数

1.核心思想

  1. 事件驱动:仅关注活跃的文件描述符,避免遍历全部描述符。

  2. 内核事件表:通过内核维护的红黑树就绪链表,实现高效的事件注册与通知。


2.核心函数

1. epoll_create - 创建 epoll 实例

#include <sys/epoll.h>int epoll_create(int size);  // size 参数已弃用(只需 >0)
  • 返回一个 epoll 文件描述符(用于后续操作)。

  • 不再使用时需用 close() 关闭。


2. epoll_ctl - 管理 epoll 事件表

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
  • 参数

    • epfdepoll_create 返回的 epoll 描述符。

    • op:操作类型:

      • EPOLL_CTL_ADD:注册新 fd。

      • EPOLL_CTL_MOD:修改已注册的 fd。

      • EPOLL_CTL_DEL:删除 fd。

    • fd:要操作的 fd(如套接字)。

    • event:指向事件结构体的指针。

  • struct epoll_event

    struct epoll_event {uint32_t     events;  // 关注的事件(按位或组合)epoll_data_t data;    // 用户数据(如关联的 fd)
    };typedef union epoll_data {void    *ptr;int      fd;uint32_t u32;uint64_t u64;
    } epoll_data_t;

3. epoll_wait - 等待事件发生

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
  • 参数

    • epfd:epoll 描述符。

    • events:输出参数,用于接收就绪事件数组。

    • maxeventsevents 数组的最大容量。

    • timeout:超时时间(毫秒),-1 表示阻塞,0 表示立即返回。

  • 返回值

    • 成功:返回就绪的 fd 数量。

    • 超时:返回 0

    • 错误:返回 -1,设置 errno


3.事件类型

事件类型说明
EPOLLIN数据可读(包括对端关闭连接)
EPOLLOUT数据可写
EPOLLERR发生错误(自动监听,无需显式设置)
EPOLLHUP对端关闭连接或读写关闭
EPOLLET边缘触发模式(默认是水平触发)
EPOLLONESHOT事件只触发一次,需重新注册才能继续监听

4.触发模式

1. 水平触发(LT,默认)
  • 特点:只要 fd 满足就绪条件,会持续通知

  • 行为:类似 select/poll,未处理的事件会重复触发 epoll_wait

  • 适用场景:简单编程模型,无需一次性处理完所有数据。

2. 边缘触发(ET)
  • 特点:仅在 fd 状态变化时通知一次

  • 行为:需一次性处理完所有数据(否则可能丢失事件)。

  • 要求:必须使用非阻塞 I/O,循环读/写直到 EAGAIN 或 EWOULDBLOCK

  • 适用场景:高性能场景,减少事件触发次数。


5.使用步骤

  1. 调用 epoll_create 创建 epoll 实例。

  2. 调用 epoll_ctl 注册需要监听的 fd 及事件。

  3. 循环调用 epoll_wait 等待事件。

  4. 处理就绪事件(如读/写数据)。

  5. 根据需求修改或删除已注册的 fd。


6.示例代码(LT 模式)

#include <sys/epoll.h>#define MAX_EVENTS 10int main() {int epfd = epoll_create1(0);  // 创建 epoll 实例struct epoll_event ev, events[MAX_EVENTS];// 注册 socket_fd 到 epoll,监听可读事件(默认 LT)ev.events = EPOLLIN;ev.data.fd = socket_fd;epoll_ctl(epfd, EPOLL_CTL_ADD, socket_fd, &ev);while (1) {int nready = epoll_wait(epfd, events, MAX_EVENTS, -1);for (int i = 0; i < nready; i++) {if (events[i].data.fd == socket_fd) {// 处理 socket 可读事件(如 accept 新连接)} else {// 处理其他 fd 的读/写事件}}}close(epfd);return 0;
}

7.优点

  1. 高效处理海量连接:时间复杂度 O(1)(就绪事件数量相关)。

  2. 无需重复注册:内核直接维护事件表。

  3. 支持边缘触发:减少无效事件通知,提高吞吐量。


8.缺点

  1. 仅限 Linux:跨平台需改用 select/poll 或 kqueue(BSD/macOS)。

  2. 编程复杂度:ET 模式需处理非阻塞 I/O 和缓冲区。


9.适用场景

  • 高并发服务器(如 Web 服务器、游戏服务器)。

  • 需要同时处理数万甚至百万级连接。

  • 追求低延迟和高吞吐量的网络应用。


10.对比 select/poll

特性select/pollepoll
时间复杂度O(n)(遍历所有 fd)O(1)(仅处理就绪事件)
最大 fd 数量有限(select 默认 1024)理论无上限(受系统资源限制)
触发模式仅水平触发(LT)支持 LT 和 ET
内存拷贝每次调用需拷贝 fd 集合到内核内核直接管理事件表
适用场景低并发或跨平台Linux 高并发

11.注意事项

  1. ET 模式必须使用非阻塞 I/O:避免因未读完数据导致线程阻塞。

  2. 避免 EPOLLONESHOT 误用:需手动重新注册事件。

  3. 内存泄漏:及时关闭不再使用的 epoll 描述符。


12.总结

epoll 是 Linux 下高性能网络编程的基石,尤其适合高并发场景。其事件驱动模型和高效的内核机制(如红黑树、就绪链表)使其在处理海量连接时性能远超 select 和 poll。若需跨平台,可结合 epoll(Linux)、kqueue(BSD/macOS)和 IOCP(Windows)实现多路复用。


三、当网卡接收到数据流程

1. 网卡接收数据(硬件层)

  1. 数据到达网卡

    • 网卡接收到数据包后,通过 DMA 直接将数据拷贝到内核内存的 环形缓冲区(Ring Buffer) 中。

    • 网卡触发 硬件中断,通知 CPU 有数据到达。

  2. 软中断处理

    • 内核通过 ksoftirqd 线程(软中断)处理数据包:

      1. 解析数据包:拆解以太网帧、IP 头、TCP/UDP 头。

      2. 关联 Socket:根据端口和 IP 找到对应的 Socket(文件描述符 fd)。

      3. 填充接收缓冲区:将数据存入该 Socket 的 接收缓冲区(Receive Buffer)


2. epoll 的事件触发(内核层)

关键数据结构
  • 红黑树(RB-Tree):存储所有通过 epoll_ctl 注册的 fd(键为 fd,值为 epoll_event)。

  • 就绪队列(Ready List):存放已就绪的 fd 对应的事件(epoll_item 结构)。

事件触发流程
  1. 检查 epoll 监听状态

    • 当数据被存入 Socket 的接收缓冲区后,内核检查该 fd 是否被某个 epoll 实例监听(即是否在红黑树中存在对应的 epoll_item)。

    • 如果是,内核会将该 fd 关联的 epoll_item 添加到 就绪队列 中,并标记事件类型(如 EPOLLIN)。

  2. 回调机制

    • epoll 通过 回调函数(Callback) 实现事件触发,而非轮询。

    • 当数据到达时,内核直接调用 ep_poll_callback 函数,将对应的 epoll_item 插入就绪队列,无需遍历红黑树。


3. 用户层获取事件(应用层)

  1. 调用 epoll_wait

    • 用户程序调用 epoll_wait 时,内核检查 就绪队列

      • 如果队列非空,直接返回就绪的 fd 列表(通过 events 数组)。

      • 如果队列为空,根据 timeout 参数决定阻塞或超时返回。

  2. 就绪队列处理

    • 内核将就绪队列中的 epoll_item 复制到用户提供的 events 数组中,并清空就绪队列。

    • 用户程序遍历 events 数组,处理每个就绪的 fd(如读取数据)。


流程总结(结合数据结构)

  1. 数据到达网卡 → DMA 到内核缓冲区 → 协议栈解析 → 填充 Socket 接收缓冲区。

  2. 检查红黑树 → 若 fd 被 epoll 监听 → 触发回调函数 → 将 epoll_item 加入就绪队列。

  3. 用户调用 epoll_wait → 内核返回就绪队列中的事件 → 应用处理数据。


性能优势的根源

  1. 红黑树的高效管理

    • 添加/删除/查找 fd 的时间复杂度为 O(log N),适合动态管理海量连接。

  2. 就绪队列的 O(1) 事件获取

    • 直接返回就绪的 fd,无需遍历所有监听的 fd(对比 select/poll 的 O(N))。

  3. 回调驱动(而非轮询)

    • 仅在实际事件发生时触发操作,避免无意义的 CPU 开销。


触发模式的影响

1. 水平触发(LT)
  • 数据未读完时:内核会持续将 fd 加入就绪队列,直到接收缓冲区为空。

  • 行为示例
    若应用只读取部分数据,下次 epoll_wait 仍会返回该 fd 的 EPOLLIN 事件。

2. 边缘触发(ET)
  • 仅在状态变化时触发:内核仅在接收缓冲区从空变为非空时,将 fd 加入就绪队列一次。

  • 行为示例
    应用必须一次性读取所有数据(直到 read 返回 EAGAIN),否则会丢失后续事件。


完整流程示例

  1. 客户端发送数据 → 网卡接收 → 内核协议栈处理 → 数据存入 Socket 接收缓冲区。

  2. 内核检查红黑树:发现该 fd 被 epoll 监听(关注 EPOLLIN 事件)。

  3. 触发回调 → 将该 fd 的 epoll_item 插入就绪队列。

  4. 用户调用 epoll_wait → 获取到该 fd 的 EPOLLIN 事件。

  5. 应用读取数据 → 若使用 ET 模式,需循环读取直到 EAGAIN

  6. 处理完毕 → 继续调用 epoll_wait 等待新事件。


总结

  • 红黑树:管理所有注册的 fd,实现高效增删改查。

  • 就绪队列:存储实际发生的事件,避免全量遍历。

  • 回调机制:数据到达时直接触发事件,减少延迟。

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

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

相关文章

基于 ‌MySQL 数据库‌对三级视图(用户视图、DBA视图、内部视图)的详细解释

基于 ‌MySQL 数据库‌对三级视图&#xff08;用户视图、DBA视图、内部视图&#xff09;的详细解释&#xff0c;结合理论与实际操作说明&#xff1a; 一、三级视图核心概念 数据库的三级视图是 ANSI/SPARC 体系结构的核心思想&#xff0c;MySQL 的实现逻辑如下&#xff1a; …

突破性能极限:DeepSeek开源FlashMLA解码内核技术解析

引言&#xff1a;大模型时代的推理加速革命 在生成式AI大行其道的今天&#xff0c;如何提升大语言模型的推理效率已成为行业焦点。DeepSeek团队最新开源的FlashMLA项目凭借其惊人的性能表现引发关注——在H800 GPU上实现580 TFLOPS计算性能&#xff0c;这正是大模型推理优化的…

ROS ur10机械臂添加140夹爪全流程记录

ROS ur10机械臂添加140夹爪 系统版本&#xff1a;Ubuntu20.04 Ros版本&#xff1a;noetic Moveit版本&#xff1a;moveit-noetic 参考博客&#xff1a; ur3robotiq ft sensorrobotiq 2f 140配置rviz仿真环境_有末端力传感器的仿真环境-CSDN博客 UR5机械臂仿真实例&#xf…

Redis速成(1)VMware虚拟机安装Redis+Session验证登录注册+MybatisPlus

课程&#xff1a;黑马程序员Redis入门到实战教程&#xff0c;深度透析redis底层原理redis分布式锁企业解决方案黑马点评实战项目_哔哩哔哩_bilibili Mybatis与MybatisPlus: 参考springboot&#xff0c;需要额外写mapper.class&#xff0c;在方法上Select等 在ssm中&#xff0c;…

thinkphp下的Job队列处理

需要think-queue扩展&#xff0c;没有的请composer安装一下 "require": {"php": ">7.2.5","topthink/framework": "^6.1","topthink/think-orm": "^2.0","topthink/think-multi-app": &qu…

2024-2025 学年广东省职业院校技能大赛 “信息安全管理与评估”赛项 技能测试试卷(五)

2024-2025 学年广东省职业院校技能大赛 “信息安全管理与评估”赛项 技能测试试卷&#xff08;五&#xff09; 第一部分&#xff1a;网络平台搭建与设备安全防护任务书第二部分&#xff1a;网络安全事件响应、数字取证调查、应用程序安全任务书任务 1&#xff1a;应急响应&…

JSON Schema 入门指南:如何定义和验证 JSON 数据结构

文章目录 一、引言二、什么是 JSON Schema&#xff1f;三、JSON Schema 的基本结构3.1 基本关键字3.2 对象属性3.3 数组元素3.4 字符串约束3.5 数值约束 四、示例&#xff1a;定义一个简单的 JSON Schema五、使用 JSON Schema 进行验证六、实战效果6.1 如何使用 七、总结 一、引…

VMware虚拟机Mac版安装Win10系统

介绍 Windows 10是由美国微软公司开发的应用于计算机和平板电脑的操作系统&#xff0c;于2015年7月29日发布正式版。系统有生物识别技术、Cortana搜索功能、平板模式、桌面应用、多桌面、开始菜单进化、任务切换器、任务栏的微调、贴靠辅助、通知中心、命令提示符窗口升级、文…

计算机网络:ICMP协议(Internet控制消息协议)介绍

目录 一、简介 二、为什么要有ICMP协议? 三、ICMP协议报文格式 四、ICMP报文的类型 4.1 差错报文 4.2 查询报文 五、ICMP报文的实际案例 5.1 Ping命令 5.2 Traceroute命令 总结 今天和大家聊聊ICMP协议相关的知识,感兴趣的可以一起了解一下! 一、简介 ICMP(Inte…

python读取sqlite温度数据,并画出折线图

需求&#xff1a; 在Windows下请用python画出折线图&#xff0c;x轴是时间&#xff0c;y轴是温度temperature 和体感温度feels_like_temperature 。可以选择县市近1小时&#xff0c;近1天&#xff0c;近1个月的。sqlite文件weather_data.db当前目录下&#xff0c;建表结构如下…

window下kafka安装

kafka下载 下载好,直接解压即可 默认是带有zookeeper(注册中心) 需要先启动zookeeper zookeeper配置 先配置下zookeeper 这个data文件夹是自定建的 随意建在哪里 注意 这里斜杠用和linux一样 启动zookeeper 进入bin/windows目录 启动zookeeper zookeeper-server-start.ba…

开发HarmonyOS NEXT版五子棋游戏实战

大家好&#xff0c;我是 V 哥。首先要公布一个好消息&#xff0c;V 哥原创的《鸿蒙HarmonyOS NEXT 开发之路 卷1&#xff1a;ArkTS 语言篇》图书终于出版了&#xff0c;有正在学习鸿蒙的兄弟可以关注一下&#xff0c;写书真是磨人&#xff0c;耗时半年之久&#xff0c;感概一下…

2月26(信息差)

&#x1f30d;思科和英伟达新旧双王联手 目标重塑网络架构抢占下沉市场 &#x1f384;全球AI大混战升温&#xff01;超越Sora的阿里万相大模型开源 家用显卡都能跑 ✨小米15 Ultra、小米SU7 Ultra定档2月27日 雷军宣布&#xff1a;向超高端进发 1.全球首个&#xff01;人形机器…

物联网通信应用案例之《智慧农业》

案例概述 在智慧农业方面&#xff0c;一般的应用场景为可以自动检测温度湿度等一系列环境情况并且可以自动做出相应的处理措施如简单的浇水和温度控制等&#xff0c;且数据情况可远程查看&#xff0c;以及用户可以实现远程控制。 基本实现原理 传感器通过串口将数据传递到Wi…

C# Unity 唐老狮 No.1 模拟面试题

本文章不作任何商业用途 仅作学习与交流 安利唐老狮与其他老师合作的网站,内有大量免费资源和优质付费资源,我入门就是看唐老师的课程 打好坚实的基础非常非常重要: Unity课程 - 游习堂 - 唐老狮创立的游戏开发在线学习平台 - Powered By EduSoho 目录 C# 1.其他类型转object类…

网络安全扫描--基础篇

前言 1、了解互联网安全领域中日趋重要的扫描技术 2、了解在不同网络场景下扫描技术手段 3、熟悉linux下系统内核防护策略并能大件一个有效的系统防护体系 4、增强工作安全意识&#xff0c;并能有效的实践于工作场景中 目录 1、熟悉主机扫描工具&#xff08;fping&#xff0c;…

P8697 [蓝桥杯 2019 国 C] 最长子序列

P8697 [蓝桥杯 2019 国 C] 最长子序列 题目 分析代码 题目 分析 先分析一波xdm 题意呢就是在s中找有多少个能和t匹配的字符&#xff0c;注意&#xff1a;连续匹配&#xff0c;输出连续的次数 欧克&#xff0c;开始分析&#xff0c;首先&#xff0c;哎~字母&#xff01;还强调…

一篇docker从入门到精通

Docker Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙盒机制&#xff0c;相互之间不会有任何接口&#xff08;类似 iP…

TCP/IP 5层协议簇:物理层

目录 1. 物理层&#xff08;physical layer&#xff09; 2. 网线/双绞线 1. 物理层&#xff08;physical layer&#xff09; 工作设备&#xff1a;网线、光纤、空气 传输的东西是比特bit 基本单位如下&#xff1a;数字信号 信号&#xff1a;【模拟信号&#xff08;放大器&a…

生成对抗网络(GAN)

生成对抗网络&#xff08;GAN&#xff09;:生成对抗网络是一种深度学习模型&#xff0c;由 Ian Goodfellow 等人在 2014 年提出。GAN由生成器和判别器组成&#xff0c;生成器生成假数据&#xff0c;判别器区分真假数据。两者通过对抗训练不断提升&#xff0c;最终生成器能够生成…