Linux网络——深入理解 epoll

news2024/10/2 22:28:02

目录

一、epoll 模型

1.1 前导知识

1.1.1 宏 offsetof

1.1.2 手动计算

1.2 epoll 模型

二、 epoll 工作模式

2.1 水平触发

特点:

2.2 边缘触发

特点:

边缘触发模式中的循环读取

结合非阻塞模式的优势


一、epoll 模型

经过了之前的学习,了解到了在 OS 内部,帮我们维护着的 epoll 模型由一棵红黑树与一个就绪队列组成,但是实际上真是如此吗?
其实并不是的,这是我们逻辑上抽象的概念,但事实并非如此。

1.1 前导知识

首先,需要思考一个问题,如果我们知道了结构体的某个成员的地址,能否得到该结构体的起始地址呢?

在这个问题上,C/C++ 为我们提供了一个宏 offsetof ,除此之外,还可以手动计算偏移量得到结构体的起始地址。

1.1.1 宏 offsetof

在C/C++中,如果知道一个结构体成员的地址,可以使用offsetof宏和指针运算来找到整个结构体的起始地址。具体来说,可以使用以下方法:

  1. 使用offsetof宏来获取结构体成员相对于结构体起始地址的偏移量。
  2. 使用指针运算,从成员的地址减去这个偏移量。

#include <stdio.h>
#include <stddef.h>

typedef struct
{
    int a;
    double b;
    char c;
} MyStruct;

int main()
{
    MyStruct myStruct;
    MyStruct* ptrToStruct = &myStruct;
                    
    // 获取成员b的地址
    double* ptrToMember = &(myStruct.b);

    // 计算结构体起始地址
    MyStruct* startAddress = (MyStruct*)((char*)ptrToMember - offsetof(MyStruct, b));

    // 输出结果
    printf("结构体起始地址: %p\n", (void*)startAddress);
    printf("原结构体地址: %p\n", (void*)ptrToStruct);

    return 0;
}

1.1.2 手动计算

只要知道结构体成员的相对位置,就可以手动计算偏移量找到结构体的起始地址。

  1. 定义结构体和成员变量: 定义一个包含多个成员的结构体,并定义一个该结构体类型的变量。

  2. 获取成员的地址: 获取某成员的地址。

  3. 计算成员相对于结构体起始地址的偏移量: 通过指针运算和类型转换,计算成员在结构体中的偏移量。

  4. 通过偏移量计算结构体的起始地址: 通过成员地址减去偏移量,计算出结构体的起始地址。

#include <stdio.h>

typedef struct
{
    int a;
    double b;
    char c;
} MyStruct;

int main()
{
    MyStruct myStruct;
    MyStruct* ptrToStruct = &myStruct;

    // 获取成员b的地址
    double* ptrToMember = &(myStruct.b);

    // 计算成员b的偏移量 (假设结构体对齐方式与平台有关,手动计算)
    size_t offset = (size_t)((char*)&(myStruct.b) - (char*)&myStruct);

    // 计算结构体起始地址
    MyStruct* startAddress = (MyStruct*)((char*)ptrToMember - offset);

    // 输出结果
    printf("结构体起始地址: %p\n", (void*)startAddress);
    printf("原结构体地址: %p\n", (void*)ptrToStruct);

    return 0;
}

1.2 epoll 模型

经过前导知识的学习,我们将现在来看一下运用前面知识形成的一个结构:

在这种结构中,next 与 prev 并不指向其他节点的头,而是指向其他节点的同一成员,经过前面的学习,我们知道通过结构体中的某个成员就可以得到结构体的起始地址,就可以访问到结构体的其他成员。

下面正式来看一下, epoll 模型中的节点。

在epoll的实现中,每个被监视的文件描述符(fd)都与一个 struct epitem 结构体实例相关联。这个结构体包含了红黑树节点(struct rb_node rbn)和双向链表节点(struct list_head rdllink)。红黑树用于快速查找和管理文件描述符,而双向链表节点则用于构建就绪队列。

struct epitem
{
    struct rb_node rbn;//红黑树节点
    struct list_head rdllink;//双向链表节点
    struct epoll_filefd ffd; //事件句柄信息
    struct eventpoll *ep; //指向其所属的 eventpoll 对象
    struct epoll_event event; //期待发生的事件类型
}

其中:

  • rbn 是红黑树节点,用于将该 epitem 插入到红黑树中。
  • rdllink 是双向链表节点,用于将该 epitem 插入到就绪队列中。

在epoll的实现中,当一个文件描述符准备好进行I/O操作时,相应的 epitem 结构体会从红黑树中取出,并插入到就绪队列中(通常是一个双向链表)。这种设计避免了额外的数据结构,因为 epitem 结构体本身既可以作为红黑树的节点,也可以作为就绪队列的节点。

所以真正的 epoll 模型,应该是类似上图这种形式,就绪队列与红黑树相辅相成。

二、 epoll 工作模式

epoll 有 2 种工作方式-水平触发(LT)和边缘触发(ET)

举例子来说,我们的数据就像是快递, OS 就像是快递小哥。当我们的快递是顺丰快递时,若未取走快递,快递小哥会等着我们并一直打电话催促我们来拿快递;当我们的快递是其他快递时,快递小哥当时给我们打电话,我们可以选择当场去拿,如果当场没去,我们的快递就会被放进菜鸟驿站

上面的顺丰就是水平触发,其他就是边缘触发。

2.1 水平触发

水平触发是 epoll 的默认工作模式。这种模式下,只要文件描述符上有未处理的事件,每次调用 epoll_wait 都会通知你。这意味着,只要有数据可读或空间可写,epoll_wait 就会返回该文件描述符。

特点:

  1. 持续通知:只要有事件未被处理,epoll_wait 每次调用都会返回。
  2. 简单易用:处理方式类似于 pollselect,更容易使用和理解。
  3. 适合阻塞式 I/O:适合处理阻塞式 I/O 操作,不容易漏掉事件。

2.2 边缘触发

边缘触发是一种高效的事件通知模式,但使用起来更加复杂。在这种模式下,只有当文件描述符从无事件到有事件变化时才会通知你。换句话说,只有当文件描述符的状态发生变化时(例如,从不可读变为可读),epoll_wait 才会返回该文件描述符。

特点:

  1. 一次性通知:只在状态变化时通知一次,如果不一次性处理完所有数据,后续不会再收到通知。
  2. 高效:避免了重复通知,减少了系统调用次数。
  3. 适合非阻塞 I/O:通常需要将文件描述符设置为非阻塞模式,避免因为没有新事件而陷入阻塞。

因为边缘触发一次性通知的特点,这倒逼着程序员一次性取走TCP缓冲区的全部数据,但是,如何保证能一次性全部处理完所有数据呢?这就要使用循环读取的方法,但是这时又会产生一个问题:

在阻塞模式下,I/O操作(如 readwrite)会一直阻塞,直到有数据可读或可以写入。这意味着在没有数据可读的情况下,read 调用会阻塞程序,直到有数据到达。一旦 I/O 阻塞,程序会因为等待 I/O 操作而停滞不前,这违背了边缘触发模式的设计理念,并会影响到整个事件驱动系统的性能。所以就需要我们将文件描述符设置为非阻塞状态。

边缘触发模式中的循环读取

在边缘触发模式下,epoll 只会在状态变化(如有新数据到达)时通知应用程序。这意味着如果程序没有一次性读取所有数据,后续不会再收到通知。因此,程序员需要使用循环来确保读取所有数据。

结合非阻塞模式的优势

在非阻塞模式下,结合边缘触发模式,程序员可以设计一个高效的事件驱动程序。使用非阻塞模式时,read 调用会立即返回,如果没有数据可读,程序不会阻塞,可以继续处理其他事件。

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

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

相关文章

什么是容器查询?分享 1 段优质 CSS 代码片段!

本内容首发于工粽号&#xff1a;程序员大澈&#xff0c;每日分享一段优质代码片段&#xff0c;欢迎关注和投稿&#xff01; 大家好&#xff0c;我是大澈&#xff01; 本文约 700 字&#xff0c;整篇阅读约需 1 分钟。 今天分享一段优质 CSS 代码片段&#xff0c;使用容器查询…

【算法设计题】实现以字符串形式输入的简单表达式求值,第2题(C/C++)

目录 第2题 实现以字符串形式输入的简单表达式求值 得分点&#xff08;必背&#xff09; 题解 1. 初始化和变量定义 2. 获取第一个数字并存入队列 3. 遍历表达式字符串&#xff0c;处理运算符和数字 4. 初始化 count 并处理加减法运算 代码详解 &#x1f308; 嗨&#xf…

你还在为PDF文件烦恼吗?试试这四款合并工具吧!

每天应对工作都是一个头两个大的&#xff0c;其中pdf的文件问题就是恼人的工作量之一了&#xff0c;这几年的工作经历下来也找了各种可以帮助解决PDF文件问题的工具&#xff0c;好在使用了一些助力我高效工作的软件&#xff0c;今天针对其中遇到的解决pdf合并问题的四款宝藏工具…

当Vercel的域名验证规则碰上JPDirect这种不配合的同学把我的脑袋擦出了火星子

文章目录 前言问题简单说明Vercel主要功能和特点 JPDirectNameServers解决方案 总结 前言 处理域名转移这件事已经过去好几天&#xff0c;终于抽出点时间来总结一下&#xff0c;解决这件事大概花了2周多时间&#xff0c;因为时差的原因导致沟通缓慢&#xff0c;今天准备长话短…

【leetcode】平衡二叉树、对称二叉树、二叉树的层序遍历(广度优先遍历)(详解)

Hi~&#xff01;这里是奋斗的明志&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f331;&#x1f331;个人主页&#xff1a;奋斗的明志 &#x1f331;&#x1f331;所属专栏&#xff1a;数据结构、LeetCode专栏 &#x1f4da;本系…

Zookeeper未授权访问漏洞

Zookeeper是分布式协同管理工具&#xff0c;常用来管理系统配置信息&#xff0c;提供分布式协同服务。Zookeeper的默认开放端口是2181。Zookeeper安装部署之后默认情况下不需要任何身份验证&#xff0c;造成攻击者可以远程利用Zookeeper&#xff0c;通过服务器收集敏感信息或者…

通信原理实验——PCM编译码

PCM编译码 实验目的 理解PCM编译码原理及PCM编译码性能熟悉PCM编译码专用集成芯片的功能和使用方法及各种时钟关系熟悉语音数字化技术的主要指标及测量方法 主要仪器设备及软件 硬件&#xff1a;多功能实验箱、示波器、导线 软件&#xff1a;无 实验原理 1. 抽样信号的量…

锅总浅析SRE

SRE简介 SRE&#xff08;Site Reliability Engineering&#xff0c;站点可靠性工程&#xff09;是由Google开发的一种运维理念和实践方法&#xff0c;其核心思想是用软件工程的方式来管理和运维系统&#xff0c;以提高系统的可靠性、效率和可扩展性。 SRE的核心理念 自动化&…

【Slf4j】项目中使用 slf4j 的好处

前言 背景 项目依赖了三方包&#xff0c;三方包有日志打印的代码。需要将三方包的日志打出来。问题 是怎么做到项目的日志格式和依赖中的日志格式保持一致的&#xff1f;结论 查阅资料后&#xff0c;发现是 slf4j 帮忙做了桥接。这里做下记录。 实验 starter 依赖 log4j主项…

【全网最全】2024年第五届“华数杯”全国大学生数学建模竞赛完整思路解析+代码+论文

我是Tina表姐&#xff0c;毕业于中国人民大学&#xff0c;对数学建模的热爱让我在这一领域深耕多年。我的建模思路已经帮助了百余位学习者和参赛者在数学建模的道路上取得了显著的进步和成就。现在&#xff0c;我将这份宝贵的经验和知识凝练成一份全面的解题思路与代码论文集合…

常见的MySQL数据库面试题

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 总结一下mysql中常…

【最新】精选8家优秀大学生AI论文写作网站

在当前的学术环境中&#xff0c;AI论文写作平台为大学生提供了极大的便利和高效性。以下是8家优秀的AI论文写作网站推荐&#xff1a; 一、千笔-AIPassPaPer 千笔-AIPassPaPer是一款AI原创论文写作平台&#xff0c;能够在10分钟内产出3万字的内容&#xff0c;并提供真实网络数据…

广州城市信息模型(CIM)白皮书学习

CIM平台定义 以建筑信息模型(BIM)、地理信息系统(GIS)、物联网(IoT)等技术为基础&#xff0c;整合城市地上地下、室内室外、历史现状未来多维多尺度信息模型数据和城市感知数据&#xff0c;构建起三维数字空间的城市信息有机综合体。 广州CIM平台建设历程 2019 年 6 月住房和…

关于手机中的红外遥控

在手机电路中&#xff0c;有这么不起眼的一部分&#xff0c;虽看似简单&#xff0c;但是却给我们的生活在一定程度上带来了极大的便捷-红外遥控部分。 其置于手机顶部&#xff0c;并在壳体处挖开一个小孔&#xff0c;用于红外信号对外界的传递。如果你感兴趣的话&#xff0c;不…

【时时三省】unity test 测试框架 使用 code blocks 移植(核心文件:unity.c)

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 目录 1&#xff0c;使用 Code::Blocks 17.12 创建工程 2&#xff0c;移植文件至该工程下&#xff1a; 移入的文件为: 被移入的文件介绍&#xff1a; 更改代码&#xff1a; 向工程添加文…

[数据集][目标检测]生产线上金属罐易拉罐正反面检测数据集VOC+YOLO格式2715张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2715 标注数量(xml文件个数)&#xff1a;2715 标注数量(txt文件个数)&#xff1a;2715 标注…

【2024年华数杯全国大学生数学建模竞赛】C题:老外游中国 问题思路分析及Python代码实现

【2024 年华数杯全国大学生数学建模竞赛】C题&#xff1a;老外游中国 问题思路分析及Python代码实现 1 题目 最近&#xff0c;“city 不 city”这一网络流行语在外国网红的推动下备受关注。随着我国过境免签政策的落实&#xff0c;越来越多外国游客来到中国&#xff0c;通过网…

【Nuxt】约定式路由和内置组件

约定式路由 手动创建&#xff1a; 或者还可以使用终端创建页面&#xff1a;nuxi-add-page npx nuxi add page about — about.vue npx nuxi add page about/index — about/index.vue <NuxtLink to"/"><button>Home</button></NuxtLink><…

宅家也能高效办公?试试这四款款远程控制神器!

因为工作时不时需要出差 &#xff0c;所以自打有出差以来遇到同事需要远程求助的情况都会想到远程控制电脑的方式&#xff0c;不仅仅解决了异地无法处理的情况&#xff0c;还能够及时快速并且零成本处理问题&#xff0c;所以今天就整理了四款很适合打工人的远程控制电脑的工具&…

C# Unity 面向对象补全计划 七大原则 之 开闭原则

本文仅作学习笔记与交流&#xff0c;不作任何商业用途&#xff0c;作者能力有限&#xff0c;如有不足还请斧正 本系列作为七大原则和设计模式的进阶知识&#xff0c;看不懂没关系 请看专栏&#xff1a;http://t.csdnimg.cn/mIitr&#xff0c;查漏补缺 1.开闭原则&#xff08;OC…