Epoll:让IO多路复用变得有趣

Epoll 是 Linux 系统中高性能的 I/O 事件通知机制,通过它可以实现对大量文件描述符的高效监控,适用于构建高并发的网络服务器。

文章目录

  • epoll介绍
    • 主要特点
    • epoll与poll、select区别
      • 效率和扩展性
      • 文件描述符数量限制
      • 工作模式
      • 小结
  • epoll常用函数
    • epoll_create
    • epoll_ctl
    • epoll_wait
  • 实例

epoll介绍

在Linux中,epoll是一种高效的I/O多路复用机制,用于监视多个文件描述符(通常是套接字)的I/O事件。它相对于传统的 select 和 poll 具有更高的效率和扩展性,因此在处理大规模并发连接时被广泛应用。

主要特点

  • 事件驱动: epoll 采用事件驱动的方式工作,当文件描述符就绪时会触发事件通知,而不需要像 select 和 poll 那样需要遍历所有文件描述符进行轮询。
  • 高效的数据结构: epoll 内部使用了红黑树和哈希表等数据结构,能够快速地插入、删除和查找文件描述符,因此在增加大量文件描述符时性能下降较少。
  • 支持大量文件描述符: epoll 能够支持大量的文件描述符,且随着文件描述符数量的增加,其性能不会线性下降,这使得它非常适合于高并发的网络编程。
  • 水平触发和边缘触发: epoll 提供了两种工作模式,即水平触发(Level-Triggered,简称 LT)和边缘触发(Edge-Triggered,简称 ET)。在 LT 模式下,只要文件描述符就绪就会通知,而在 ET 模式下,只有当文件描述符的状态变化时才会通知。

epoll与poll、select区别

效率和扩展性

  • select 和 poll: 在调用时需要将文件描述符集合从用户态拷贝到内核态,造成了性能损耗。而且随着文件描述符数量的增加,它们的性能会线性下降,对于大规模并发连接的情况表现不佳。
  • epoll: 使用事件驱动的方式工作,能够高效地监视大量的文件描述符而不会因文件描述符数量增加导致性能下降,因此在处理大规模并发连接时具有更高的效率和扩展性。

文件描述符数量限制

  • select: 通常限制为 1024 个文件描述符(32位机器默认为1024,64位默认为2048),因为使用固定大小的位图来表示文件描述符状态,当文件描述符数量较大时会带来额外的开销。
  • poll: 文件描述符数量的限制取决于系统的配置。
  • epoll: 没有明显的文件描述符数量限制,能够支持非常大的文件描述符数量,因为它内部使用红黑树和哈希表等数据结构,能够快速地处理大量的文件描述符。

工作模式

  • select 和 poll: 只提供了一种工作模式,即水平触发(Level-Triggered),无法区分文件描述符的状态变化,只要文件描述符就绪就会通知。
  • epoll: 提供了两种工作模式,即水平触发和边缘触发(Edge-Triggered)。在边缘触发模式下,只有当文件描述符的状态变化时才会通知,能够更精确地控制事件通知的时机。

小结

poll模型的效率不如epoll,一般在fd数量比较多,但某段时间内,就绪事件fd数量较少的情况下,epoll才会体现出它的优势,也就是说socket连接数量较大时而活跃连接较少时epoll模型更高效。

epoll常用函数

在 Linux 下,epoll 提供了一些常用的函数来实现 I/O 多路复用,以下是几个常用的 epoll 函数及其功能介绍:

epoll_create

int epoll_create(int size);
  • 功能:创建一个 epoll 实例,返回一个文件描述符,用于标识该 epoll 实例。
  • 参数:size 表示 epoll 实例中能够同时处理的文件描述符数量,该参数在 Linux 2.6.8 之后已经被忽略,可以传入任意大于 0 的值。
  • 返回值:成功时返回一个新的文件描述符,失败时返回 -1。

epoll_ctl

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
  • 功能:向 epoll 实例中注册或修改事件。
  • 参数
    • epfd:epoll 实例的文件描述符。
    • op:表示对事件进行的操作,可以是 EPOLL_CTL_ADD(添加新的文件描述符)、EPOLL_CTL_MOD(修改已经注册的文件描述符)、EPOLL_CTL_DEL(从 epoll 实例中删除文件描述符)。当取值是EPOLL_CTL_DEL,第四个参数event忽略不计,可以设置为NULL。
    • fd:需要注册或修改事件的文件描述符。
    • event:指向 epoll_event 结构体的指针,描述了需要注册的事件类型和文件描述符相关的数据。
  • 返回值:成功时返回 0,失败时返回 -1。

epoll_event结构体如下:

struct epoll_event {uint32_t     events; // 事件类型,需要检测的fd事件,取值与poll函数一样epoll_data_t data; // 用户自定义数据
};typedef union epoll_data {void    *ptr; // 指向用户数据的指针int      fd;  // 文件描述符uint32_t u32;uint64_t u64;
} epoll_data_t;

events:用来描述文件描述符上注册的事件类型,可以是以下的一个或多个值的组合:

  • EPOLLIN:表示对应的文件描述符可以读(包括对端 Socket 正常关闭)。
  • EPOLLOUT:表示对应的文件描述符可以写。
  • EPOLLRDHUP:表示对应的文件描述符被对端关闭,或者对端关闭了写操作。
  • EPOLLPRI:表示对应的文件描述符有紧急数据可读。
  • EPOLLERR:表示对应的文件描述符发生错误。
  • EPOLLHUP:表示对应的文件描述符被挂起。
  • EPOLLET:设置边缘触发模式(Edge-Triggered),默认为水平触发模式(Level-Triggered)。

epoll_wait

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
  • 功能:等待文件描述符上的 I/O 事件,并将就绪的文件描述符和事件信息存储到 events 数组中。
  • 参数
    • epfd:epoll 实例的文件描述符。
    • events:用于存储就绪事件的 epoll_event 结构体数组。
    • maxevents:events 数组的大小,表示最多能够存储多少个就绪事件。
    • timeout:超时时间,单位为毫秒,-1 表示永久阻塞直到有事件发生,0 表示立即返回,其他正数表示等待指定的毫秒数。
  • 返回值:返回就绪事件的数量,失败时返回 -1。

实例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>#define MAX_EVENTS 10
#define PORT 8888int main() {int server_fd, client_fd, epoll_fd, nfds, n;struct epoll_event event, events[MAX_EVENTS];struct sockaddr_in server_addr, client_addr;socklen_t client_len = sizeof(client_addr);// 创建 socketif ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {perror("socket");exit(EXIT_FAILURE);}// 设置 server 地址信息memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = htonl(INADDR_ANY);server_addr.sin_port = htons(PORT);// 绑定 server 地址if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("bind");exit(EXIT_FAILURE);}// 监听连接if (listen(server_fd, 5) == -1) {perror("listen");exit(EXIT_FAILURE);}// 创建 epoll 实例if ((epoll_fd = epoll_create1(0)) == -1) {perror("epoll_create1");exit(EXIT_FAILURE);}// 将 server_fd 添加到 epoll 实例中event.events = EPOLLIN;event.data.fd = server_fd;if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) == -1) {perror("epoll_ctl: server_fd");exit(EXIT_FAILURE);}while (1) {nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);if (nfds == -1) {perror("epoll_wait");exit(EXIT_FAILURE);}for (n = 0; n < nfds; ++n) {if (events[n].data.fd == server_fd) {  // 有新连接client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len);if (client_fd == -1) {perror("accept");exit(EXIT_FAILURE);}// 将新的 client_fd 添加到 epoll 实例中event.events = EPOLLIN;event.data.fd = client_fd;if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &event) == -1) {perror("epoll_ctl: client_fd");exit(EXIT_FAILURE);}} else {  // 有数据可读char buffer[1024];int bytes_recv = recv(events[n].data.fd, buffer, sizeof(buffer), 0);if (bytes_recv <= 0) {  // 客户端断开连接close(events[n].data.fd);} else {// 回显收到的消息send(events[n].data.fd, buffer, bytes_recv, 0);}}}}close(server_fd);return 0;
}

参考链接:

  • https://blog.csdn.net/m0_67392182/article/details/124487784
  • https://www.zhihu.com/tardis/bd/art/159135478?source_id=1001
  • https://blog.51cto.com/morris131/6216788
  • https://www.cnblogs.com/xuewangkai/p/11158576.html

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

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

相关文章

苹果ipa内侧分发可以通过哪些方法

苹果ipa内侧分发可以通过使用苹果企业签名、云服务分发平台、TestFlight分发等方式实现。 对于企业签名&#xff0c;它适合用于公司内部员工使用的应用&#xff0c;或者需要快速安装和使用的应用。开发者可以在苹果开发者中心生成企业级证书&#xff0c;然后将应用打包成IPA文…

如何在3dMax中使用Python返回场景内所有对象的列表?

如何在3dMax中使用Python返回场景内所有对象的列表&#xff1f; 3dMax支持开发基于Python的工具和扩展&#xff0c;因此可以对其进行自定义并将其集成到现代数字内容创建管道中。为此&#xff0c;3dMax集成了Python 3.9解释器&#xff0c;并通过pymxs API公开了3dMax的丰富功能…

如何有效的禁止Google Chrome自动更新?

禁止Chrome自动更新 1、背景2、操作步骤 1、背景 众所周知&#xff0c;当我们在使用Selenium进行Web自动化操作&#xff08;如爬虫&#xff09;时&#xff0c;一般会用到ChromeDriver。然而Driver的更新速度明显跟不上Chrome的自动更新。导致我们在使用Selenium进行一些操作时就…

工业交换机的六种分类

工业交换机可以按照不同的标准进行分类&#xff0c;具体有六种分类方法。我们今天就来简单了解一下这六种分类方法&#xff0c;它们分别是&#xff1a;工业交换机的管理标准、工业交换机的结构标准、工业交换机的网络位置、工业交换机的传输速率、工业交换机的工作协议以及工业…

[软件安装]anaconda安装

anaconda安装 以下是在Linux下安装anaconda的详细步骤&#xff1a; 首先&#xff0c;在anaconda官网上下载适用于Linux的anaconda安装包。 打开终端&#xff0c;进入下载目录并解压安装包。 执行以下命令进入安装程序&#xff1a;bash Anaconda3-2021.05-Linux-x86_64.sh …

提升--09-1--AQS底层逻辑实现

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、怎么解释AQS是什么&#xff1f;AQS的本质是JUC包下一个抽象类&#xff0c;AbstractQueuedSynchronizer &#xff08;抽象的队列式同步器&#xff09; 二、AQS核…

四川芸鹰蓬飞:抖店运营的时候注意什么?

抖店作为一个短视频平台&#xff0c;吸引了越来越多的商家加入。在抖店上进行有效的运营是提高销量和曝光度的关键。那么&#xff0c;抖店怎么设置运营呢&#xff1f;有哪些方法可以帮助商家在这个竞争激烈的平台上脱颖而出呢&#xff1f; 一、抖店怎么设置运营&#xff1f; 首…

三点的最近距离

题目描述 题目中会给你三个整数 a,b,c,表示三个点在数轴上所处的位置。对于每一个点&#xff0c;你最多可以移动一次&#xff0c;也可以选择不移动&#xff0c;现在请你编写代码计算&#xff0c;移动后三个点的最小的距离和为多少&#xff1f; 输入输出格式 输入格式 一行三…

微服务实战系列之加密RSA

前言 在这个时代&#xff0c;我们选择的人生目标已丰富多彩&#xff0c;秉持的人生态度也千差万别&#xff1a; 除了吃喝玩乐&#xff0c;还有科技探索&#xff1b; 除了CityWalk&#xff0c;还有“BookWalk”&#xff1b; 除了走遍中国&#xff0c;还有走遍世界&#xff1b; …

118. 杨辉三角 --力扣 --JAVA

题目 给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 解题思路 List的首位是0&#xff0c;而行数的首位是1&#xff0c;所以我们在进行行数循环时需要小于numRows&#xff0c;而在统…

Selenium自动化测试详解

最近也有很多人私下问我&#xff0c;selenium学习难吗&#xff0c;基础入门的学习内容很多是3以前的版本资料&#xff0c;对于有基础的人来说&#xff0c;3到4的差别虽然有&#xff0c;但是不足以影响自己&#xff0c;但是对于没有学过的人来说&#xff0c;通过资料再到自己写的…

Spring-IOC-Spring6和JUnit5集成

1、父工程pom.xml <properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring.version>…

【FLink】水位线(Watermark)

目录 1、关于时间语义 1.1事件时间 1.2处理时间​编辑 2、什么是水位线 2.1 顺序流和乱序流 2.2乱序数据的处理 2.3 水位线的特性 3 、水位线的生成 3.1 生成水位线的总体原则 3.2 水位线生成策略 3.3 Flink内置水位线 3.3.1 有序流中内置水位线设置 3.4.2 断点式…

【shell】条件语句

一、测试 1.1文件测试test test命令是内部命令 test的语法 test 条件表达式 [ 条件表达式 ] test 选项 文件 -d &#xff1a;判断是否是目录 -f &#xff1a;判断是否是普通文件 -b &#xff1a;判断是否是块设备 -c &#xff1a;判断是否是字符设备 -e &#xff1a;判断是否…

【Python】给出一个包含n个整数的数列,问整数a在数列中的第一次出现是第几个。

问题描述 给出一个包含n个整数的数列&#xff0c;问整数a在数列中的第一次出现是第几个。 输入格式 第一行包含一个整数n。 第二行包含n个非负整数&#xff0c;为给定的数列&#xff0c;数列中的每个数都不大于10000。 第三行包含一个整数a&#xff0c;为待查找的数。 输出格式…

rv1126-rv1109-openssh

这是一个工具&#xff0c;可以通过ssh远程登录来操作&#xff0c;非常逆天&#xff01; 于是rv1109代码自身自带有openssh 所以只需要打开config即可 diff --git a/buildroot/configs/rockchip_rv1126_rv1109_spi_nand_defconfig b/buildroot/configs/rockchip_rv1126_rv1109…

数据库迁移脚本

数据库迁移脚本 这次使用node.js作为工具去做 至于为啥用node.js?? 可能是js在异步操作上非常高效? (但它仍然是单线程的&#xff0c;对于 CPU 密集型的操作可能不如其他语言。) 本质就是先查再插 例子&#xff1a; {"name": "数据库迁移","…

Blender中的集合(collection)概念

集合是一种逻辑上的分组方式&#xff0c;它可以让你把一些相似或相关的对象放在一起&#xff0c;而不影响它们的变换关系&#xff08;不像父子关系那样&#xff09;。集合可以用来简化你的场景&#xff0c;或者方便你在不同的文件或场景之间进行追加或链接。 集合有以下的特点…

c 文本终端直接写framebuffer 显示直线

根据这思路&#xff0c;操作framebuffer 显示图片和视频 #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <string.h> #include <…

Android codec2 视频框架之输出端的内存管理

文章目录 前言setSurfacestart从哪个pool中申请buffer解码后框架的处理流程renderOutbuffer 输出显示 前言 输出buffer整体的管理流程主要可以分为三个部分&#xff1a; MediaCodc 和 应用之间的交互 包括设置Surface、解码输出回调到MediaCodec。将输出buffer render或者rele…