高级I/O知识分享【epoll || Reactor ET,LT模式】
博客主页:花果山~程序猿-CSDN博客
文章分栏:Linux_花果山~程序猿的博客-CSDN博客
关注我一起学习,一起进步,一起探索编程的无限可能吧!让我们一起努力,一起成长!

目录
一,接口
epoll_create
epoll_ctl
event 事件类型:
epoll_wait
二,epoll优点(相较select,poll)
三,epoll有2种工作方式
如何理解两种工作方式:(快递员例子)
水平触发Level Triggered 工作模式
边缘触发Edge Triggered工作模式
epoll使用场景
epoll中的惊群问题(选学)
ET模式使用思路
嗨!收到一张超美的图,愿你每天都能顺心!

一,接口

epoll_create
epoll_create(size_t size)
用于创建一个epoll文件描述符,返回一个非负整数表示新创建的epoll实例的文件描述符。size是一个建议值,表示最初能容纳多少个事件,但实际上内核可能会忽略此参数。
- 参数:
size:建议的初始事件槽的数量,但在现代内核版本中此参数几乎无用,内核会根据需要动态调整。
epoll_ctl
epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
用于向epoll实例添加、修改或删除文件描述符的监听事件。
- 参数:
epfd:epoll_create返回的epoll文件描述符。op:操作类型,可以是EPOLL_CTL_ADD(添加)、EPOLL_CTL_MOD(修改)、EPOLL_CTL_DEL(删除)。fd:需要操作的文件描述符。event:指向struct epoll_event结构体的指针,包含需要监控的事件类型。
event 事件类型:
- EPOLLIN - 表示描述符可读(例如,有数据可读取)。
- EPOLLOUT - 表示描述符可写(例如,可以发送数据)。
- EPOLLERR - 表示描述符有错误。
- EPOLLHUP - 表示描述符挂起(例如,对端关闭了连接)。
- EPOLLET - 这是一个边缘触发模式标志,不是事件类型,但它可以与其他事件类型结合使用,以改变事件检测的行为。
- EPOLLONESHOT - 这个标志让 epoll_wait() 在第一次匹配到这个事件后就不再为这个文件描述符报告该事件,直到 epoll_ctl() 再次修改此文件描述符的监听条件。
- EPOLLEXCLUSIVE - 当设置此标志时,如果多个进程或线程尝试等待同一个事件,那么仅有一个等待者会被唤醒
epoll_wait
epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)
等待已注册文件描述符上的I/O事件发生,并返回就绪事件的数目。
- 参数:
epfd:epoll_create返回的epoll文件描述符。events:一个指向epoll_event数组的指针,用于返回就绪事件。maxevents:最大可返回的就绪事件数。timeout:等待的超时时间(毫秒为单位)。如果设置为负数或0,则epoll_wait立即返回;如果大于0,则表示等待的时间。
结构体epoll_event:

从底层原理理解三接口负责的功能图:

struct eventpoll{ .... /*红黑树的根节点,这颗树中存储着所有添加到epoll中的需要监控的事件*/ struct rb_root rbr; /*双链表中则存放着将要通过epoll_wait返回给用户的满足条件的事件*/ struct list_head rdlist; ....
}; 每一个epoll对象都有一个独立的eventpoll结构体,用于存放通过epoll_ctl方法向epoll对象中添加进来的事件,这些事件都会挂载在红黑树中,如此,重复添加的事件就可以通过红黑树而高效的识别出来(红黑树的插入时间效率是lgn,其中n为树的高度). 而所有添加到epoll中的事件都会与设备(网卡)驱动程序建立回调关系,也就是说,当响应的事件发生时会调用这个回调方法.
struct epitem{ struct rb_node rbn;//红黑树节点 struct list_head rdllink;//双向链表节点 struct epoll_filefd ffd; //事件句柄信息 struct eventpoll *ep; //指向其所属的eventpoll对象 struct epoll_event event; //期待发生的事件类型
}
如何理解参数epfd的作用?

总结一下, epoll的使用过程就是三部曲:
- 调用epoll_create创建一个epoll句柄;
- 调用epoll_ctl, 将要监控的文件描述符进行注册;
- 调用epoll_wait, 等待文件描述符就绪;
二,epoll优点(相较select,poll)
- 接口使用方便: 虽然拆分成了三个函数, 但是反而使用起来更方便高效. 不需要每次循环都设置关注的文件,描述符, 也做到了输入输出参数分离开
- 数据拷贝轻量: 只在合适的时候调用 EPOLL_CTL_ADD 将文件描述符结构拷贝到内核中, 这个操作并不频繁(而select/poll都是每次循环都要进行拷贝)
- 事件回调机制: 避免使用遍历, 而是使用回调函数的方式, 将就绪的文件描述符结构加入到就绪队列中, epoll_wait 返回直接访问就绪队列就知道哪些文件描述符就绪. 这个操作时间复杂度O(1). 即使文件描述符数目很多, 效率也不会受到影响。
- 没有数量限制: 文件描述符数目无上限
三,epoll有2种工作方式
如何理解两种工作方式:(快递员例子)
LT: 当你的外卖(数据)到时,外卖员(底层)会一直给你打电话(通知)直到你下来将你的所有外卖都取走(数据拿走 )。ET: 外卖来时,外卖员(底层)只给你打一次电话,你如果不下来取,外卖员(底层)不会再通知你,你的外卖(数据)就再也拿不到了。
比较标准的解释:
水平触发Level Triggered 工作模式
epoll 默认状态下就是 LT 工作模式:
- 当epoll检测到socket上事件就绪的时候, 可以不立刻进行处理. 或者只处理一部分. 如由于只读了1K数据, 缓冲区中还剩1K数据, 在第二次调用 epoll_wait 时, epoll_wait 仍然会立刻返回并通知socket读事件就绪. 直到缓冲区上所有的数据都被处理完, epoll_wait 才不会立刻返回.(一直通知你直到数据全部取走)
- 支持阻塞读写和非阻塞读写
边缘触发Edge Triggered工作模式
- 当epoll检测到socket上事件就绪时, 必须立刻处理. 如上面的例子, 虽然只读了1K的数据, 缓冲区还剩1K的数据, 在第二次调用 epoll_wait 的时候, epoll_wait 不会再返回了. 也就是说, ET模式下, 文件描述符上的事件就绪后, 只有一次处理机会.(ET模式下,只有一次处理机会,这样倒逼程序员,要一次取完所有的数据)
- ET的性能比LT性能更高( 相同的运行时间内epoll_wait 返回的次数少了很多== 无效通知减少 == 增加其他socket通知的数量). Nginx默认采用ET模式使用epoll.
- 只支持非阻塞的读写
epoll使用场景
- 对于多连接, 且多连接中只有一部分连接比较活跃时, 比较适合使用epoll.
epoll中的惊群问题(选学)
ET模式使用思路
1.epoll_ctl时添加的文件描述符,需要添加设置 EPOLLET,这样一旦事件就绪,通过epoll_wait报告一次。2.将需要设置的fd,如listen_socket,设置为非阻塞式;在通过accept系统调用时进行轮询,直到资源被全部提取后,才结束轮询。(采用非阻塞式,就是为了避免一次未取完资源,ET模式下,事件不再通知,导致事件资源丢失)——>可参考fcntl接口的非阻塞例子例如:这个监听套接字的例子
选择ET和LT
选择哪种模式取决于具体的应用场景和需求。如果你的应用程序需要处理大量并发连接,并且对实时性要求较高,那么 ET 模式可能是更好的选择。如果你的应用程序需要处理长时间存在的连接,并且更关注稳定性,那么 LT 模式可能是更好的选择。
用ET模式优化自主web服务器
Apache 和 Nginx 是两款广泛使用的 Web 服务器软件,它们在处理大量并发连接方面表现出色。为了实现高效的并发处理,这两款服务器都利用了 Linux 内核提供的高性能 I/O 多路复用机制 epoll。
- Apache:通常使用 Level Triggered (LT) 模式,因为它提供了更好的稳定性和易用性。
- Nginx:通常使用 Edge Triggered (ET) 模式,因为它提供了更高的性能和实时性。
框架图
优化心得总结
读事件思维逻辑:
epoll 的事件队列中,随后用户可以通过不断轮询 epoll_wait 函数来获取并处理这些事件(如处理方法监听套接字上的 accept 操作)。
写事件思维逻辑:
当一个套接字的发送缓冲区满时,写操作会被阻塞。内核维护了一个发送缓冲区的状态,当缓冲区中有足够的空间可以写入数据时,内核会将该文件描述符标记为可写(即 EPOLLOUT 事件就绪)。
关于写事件逻辑理解:
1. 刚连接时是否需要设置写事件?
当一个套接字刚刚建立连接时,通常情况下发送缓冲区是有空间的。但是,为了确保应用程序能够及时响应写操作,通常的做法是在连接建立后立即设置写事件。这样做有几个好处:
- 立即响应:如果发送缓冲区确实有空间,那么设置写事件可以确保应用程序能够立即响应写操作。这有助于提高应用的响应速度。
- 预防缓冲区满的情况:即使当前缓冲区有空间,设置写事件可以防止未来缓冲区满时错过写事件。在 ET 模式下,如果没有设置写事件,当缓冲区满时,应用程序将不会收到
EPOLLOUT事件,从而可能导致数据积压。
2. 在写操作被阻塞时设置写事件?
如果你在写操作被阻塞时才设置写事件,可能会导致以下问题:
- 事件丢失:在 ET 模式下,如果写操作被阻塞,并且在设置写事件之前缓冲区有了空间,那么这个事件可能会被丢失。因为 ET 模式只会报告一次事件,除非应用程序显式地清除事件状态。
- 延迟响应:如果在写操作被阻塞时才设置写事件,可能会导致响应延迟。因为此时缓冲区已经有空间了,但应用程序还没有设置写事件,所以不会立即得到通知。
3. 刚连接时设置写事件是否会立即触发一次写事件?
当一个套接字刚刚建立连接时,发送缓冲区通常有空间。在这种情况下,设置写事件确实可能会立即触发一次写事件。然而,这是预期的行为,处理起来比较简单。
异常事件逻辑:
在epoll的ET模式下,想要主要触发异常事件(如:EPOLLERR ,EPOLLHUP),可以制造错误条件达到目的。比如通过主动close文件描述符,那么EPOLLHUP事件会被触发。
总结一下:
LT(水平触发):
-
EPOLLIN 触发条件:
读缓冲区有数据就一直触发(即epoll_wait时能检测到),没有就不触发。 -
EPOLLOUT 触发条件:
写缓冲区有空间可写,则一直触发。
ET(边缘触发)
EPOLLIN 触发条件:
1. 当读 buff 从 空 -> 不空 时,触发;
2. 当有新数据到达时,即读 buff 数据由 少 -> 多 时,触发;
3. 当读 buff 有数据可读时,我们不处理,但是对相应fd进行epoll_ctl重新注册epoll_mod IN事件时,触发。
EPOLLOUT 触发条件:
1. 当写 buff 从 满 -> 不满 时,触发;
2. 当有数据被送走时,即写 buff 数据由 多 -> 少 时,触发;
3. 当写 buff 有数据,但是我们没处理(没发送出去),但是对相应fd进行epoll_ctl重新注册epoll_mod OUT事件时,触发。
结语
本小节就到这里了,感谢小伙伴的浏览,如果有什么建议,欢迎在评论区评论,如果给小伙伴带来一些收获,请动动你发财的小手点个免费的赞,你的点赞和关注永远是博主创作的动力源泉。
相关文章:
高级I/O知识分享【epoll || Reactor ET,LT模式】
博客主页:花果山~程序猿-CSDN博客 文章分栏:Linux_花果山~程序猿的博客-CSDN博客 关注我一起学习,一起进步,一起探索编程的无限可能吧!让我们一起努力,一起成长! 目录 一,接口 epo…...
Matlab 的.m 文件批量转成py文件
在工作中碰到了一个问题,需要将原来用matlab gui做出来的程序改为python程序,因为涉及到很多文件,所以在网上搜了搜有没有直接能转化的库。参考了【Matlab】一键Matlab代码转python代码详细教程_matlab2python-CSDN博客 这位博主提到的matla…...
【软考】传输层协议TCP与UDP
目录 1. TCP1.1 说明1.2 三次握手 2. UDP3. 例题3.1 例题1 1. TCP 1.1 说明 1.TCP(Transmission Control Protocol,传输控制协议)是整个 TCP/IP 协议族中最重要的协议之一。2.它在IP提供的不可靠数据服务的基础上为应用程序提供了一个可靠的、面向连接的、全双工的…...
Arthas dashboard(当前系统的实时数据面板)
文章目录 二、命令列表2.1 jvm相关命令2.1.1 dashboard(当前系统的实时数据面板) 二、命令列表 2.1 jvm相关命令 2.1.1 dashboard(当前系统的实时数据面板) 使用场景: 在 Arthas 中,dashboard 命令用于提…...
微服务保护之熔断降级
在微服务架构中,服务之间的调用是通过网络进行的,网络的不确定性和依赖服务的不可控性,可能导致某个服务出现异常或性能问题,进而引发整个系统的故障,这被称为 微服务雪崩。为了防止这种情况发生,常用的一些…...
TomCat乱码问题
TomCat控制台乱码问题 乱码问题解决: 响应乱码问题 向客户端响应数据: package Servlet;import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servl…...
依赖库查看工具Dependencies
依赖库查看工具:Dependencies Dependencies 是一款 Windows 平台下的静态分析工具,用来分析可执行文件(EXE、DLL 等)所依赖的动态链接库(DLL)。它可以帮助开发者和系统管理员快速查找程序在运行时可能缺少的…...
Kafka 下载安装及使用总结
1. 下载安装 官网下载地址:Apache Kafka 下载对应的文件 上传到服务器上,解压 tar -xzf kafka_2.13-3.7.0.tgz目录结果如下 ├── bin │ └── windows ├── config │ └── kraft ├── libs ├── licenses └── site-docs官方文档…...
python实现多个pdf文件合并
打印发票时,需要将pdf合并成一个,单页两张打印。网上一些pdf合并逐渐收费,这玩意儿都能收费?自己写一个脚本使用。 实现代码: 输入pdf文件夹路径data_dir,统计目录下的“合并后的PDF”文件夹下,…...
2409js,学习js2
原文 全局对象 function sayHi() {alert("Hello"); }// 全局对象的函数. window.sayHi(); alert(window.innerHeight);更改背景 document.body.style.background "red";setTimeout(() > document.body.style.background "", 1000);当前地…...
SpellBERT: A Lightweight Pretrained Model for Chinese Spelling Check(EMNLP2021)
SpellBERT: A Lightweight Pretrained Model for Chinese Spelling Check(EMNLP2021) 一.概述 作者认为许多模型利用预定义的混淆集来学习正确字符与其视觉上相似或语音上相似的误用字符之间的映射,但映射可能是域外的。为此,我们提出了SpellBERT&…...
【机器学习】--- 决策树与随机森林
文章目录 决策树与随机森林的改进:全面解析与深度优化目录1. 决策树的基本原理2. 决策树的缺陷及改进方法2.1 剪枝技术2.2 树的深度控制2.3 特征选择的优化 3. 随机森林的基本原理4. 随机森林的缺陷及改进方法4.1 特征重要性改进4.2 树的集成方法优化4.3 随机森林的…...
[SAP ABAP] 创建域
我们可以使用事务码SE11创建域 输入要创建的域的名称,然后点击创建 输入简短描述,选择数据类型和输入字符数 激活并保存域,创建的域才能够生效 补充扩展练习 创建一个有关"性别"基本信息的域...
STM32 通过 SPI 驱动 W25Q128
目录 一、STM32 SPI 框图1、通讯引脚2、时钟控制3、数据控制逻辑4、整体控制逻辑5、主模式收发流程及事件说明如下: 二、程序编写1、SPI 初始化2、W25Q128 驱动代码2.1 读写厂商 ID 和设备 ID2.2 读数据2.3 写使能/写禁止2.4 读/写状态寄存器2.5 擦除扇区2.6 擦除整…...
C#进阶-基于雪花算法的订单号设计与实现
在现代电商系统和分布式系统中,高效地生成全局唯一的订单号是一个关键需求。订单号不仅需要唯一性,还需要具备一定的趋势递增性,以满足数据库索引和排序的需求。本文将介绍如何在C#中使用雪花算法(Snowflake)设计和实现…...
低版本SqlSugar的where条件中使用可空类型报语法错误
SQLServer数据表中有两列可空列,均为数值类型,同时在数据库中录入测试数据,Age和Height列均部分有值。 使用SqlSugar的DbFirst功能生成数据库表类,其中Age、Height属性均为可空类型。 开始使用的SqlSugar版本较低&…...
跨游戏引擎的H5渲染解决方案(腾讯)
本文是腾讯的一篇H5 跨引擎解决方案的精炼。 介绍 本文通过实现基于精简版的HTML5(HyperText Mark Language 5)来屏蔽不同引擎,平台底层的差异。 好处: 采用H5的开发方式,可以将开发和运营分离,运营部门自…...
docker构建java镜像,运行镜像出现日志 no main manifest attribute, in /xxx.jar
背景 本文主要是一个随笔,记录一下出现"no main manifest attribute"的解决办法 问题原因 主要是近期在构建一个镜像,在镜像构建成功后,运行一直提示"no main manifest attribute",当时还在想,是不是Dockerfile写错了,后来仔细检查了一下,发现是…...
react + antDesignPro 企业微信扫码登录
效果 实现步骤 1、项目中document.ejs文件引入企微js链接 注意:技术栈是使用的react antDesignPro,不同的技术栈有不同的入口文件(如vue在html文件引入) <script src"https://wwcdn.weixin.qq.com/node/wework/wwopen/j…...
Go-知识-定时器
Go-知识-定时器 1. 介绍2. Timer使用场景2.1 设定超时时间2.2 延迟执行某个方法 3. Timer 对外接口3.1 创建定时器3.2 停止定时器3.3 重置定时器3.4 After3.5 AfterFunc 4. Timer 的实现原理4.1 Timer数据结构4.1.1 Timer4.1.2 runtimeTimer 4.2 Timer 实现原理4.2.1 创建Timer…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...
