select、epoll相关

news2024/12/23 13:39:48
  • select函数:
int select(
    int nfds,                     // 监控的文件描述符集里最大文件描述符加1
    fd_set *readfds,              // 监控有读数据到达文件描述符集合,引用类型的参数
    fd_set *writefds,             // 监控写数据到达文件描述符集合,引用类型的参数
    fd_set *exceptfds,            // 监控异常发生达文件描述符集合,引用类型的参数
    struct timeval *timeout);     // 定时阻塞监控时间

select的执行流程:

如上图,假设进程A同时要监听socket文件描述符3、4、5,如果这三个连接都没有数据到达时,则进程A会让出CPU,进入阻塞状态,同时会将进程A的文件描述符和被唤醒时用到的回调函数组成等待队列加入到socket3、4、5的进程等待队列中。注意,这是select调用时,被监控的文件描述符集合(readfds/writefds/exceptfds)会从用户空间拷贝到内核空间。

当网卡接收网线传来的数据,经过DMA传输,IO通路选择等处理后,将收到的数据写入到内存,网卡将接收到的网络数据写入内存后,网卡向CPU发出一个中断信号,CPU捕获这个信号后,执行相应的中断处理程序,中断处理程序主要做了两件事:

1、将网络数据写入到对应socket的数据接收队列里;

2、唤醒队列中的等待进程A,重新将进程A放入CPU的运行队列中。

假设socket3、5有数据到达网卡(注意此时select调用结束时,被监控的文件描述符集合会从内核空间拷贝到用户空间,全量拷贝。),则执行以下流程:

由此可见,select有以下缺点:

1、性能开销大:①调用select时会陷入内核,这时需要将被监听的文件描述符从用户空间拷贝到内核空间;select执行完毕后,还需要将文件描述符从内核空间拷贝到用户空间,高并发场景下这样的拷贝会消耗极大资源(epoll优化为不拷贝);②进程被唤醒后,不知道哪些连接已经就绪(即收到数据),需要遍历传递出来的所有文件描述符的每一位,不管他们是否就绪(epoll优化为异步事件通知);③select只返回就绪文件的个数,具体哪个文件可读还需要遍历(epoll优化为只返回就绪的文件描述符,无需做无效的遍历)

2、同时能监控的文件描述符太少,受限于sizeof(fd_set)大小,在编译内核时就确定了且无法更改。一般32位操作系统是1024,64位操作系统是2048

  • epoll相关函数:
int epoll_create(int size);   // 创建一个 eventpoll 内核对象

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);   // 将连接到socket对象添加到 eventpoll 对象上,epoll_event是要监听的事件

int epoll_wait(int epfd, struct epoll_event *events,
               int maxevents, int timeout);      // 等待连接 socket 的数据是否到达

1、epoll_create(int size):

创建一个struct evenpoll内核对象,evenpoll对象的内部结构如下:

evenpoll主要包含三个字段:

struct eventpoll {

    //sys_epoll_wait用到的等待队列
    wait_queue_head_t wq;

    //接收就绪的描述符都会放到这里
    struct list_head rdllist;

    //红黑树,管理用户进程下添加进来的所有 socket 连接
    struct rb_root rbr;

    ......
}

①wq:等待队列链表,如果当前进程没有数据需要处理,会把当前进程描述符和回调函数default_wake_function构造一个等待队列项,放入当前wq队列,软中断数据就绪的时候,会通过wq来找到阻塞在epoll对象上的用户进程;

②rbr:一颗红黑树,管理用户进程下添加进来的所有socket连接;

③rdlist:就绪的文件描述符链表。当有socket的连接数据就绪时,内核会把就绪的连接放到rdlist链表里。这样应用进程只需要判断链表就能找出就绪进程,而不用取遍历整颗树。

2、epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)添加socket:

epoll_ctl函数主要把服务端和客户端建立的socket连接注册到eventpoll里,会做三件事:

①创建要给epitem对象,主要包含两个字段:socket fd,连接的文件描述符;所属的eventpoll对象的指针;

struct epitem {

    //红黑树节点
    struct rb_node rbn;

    //socket文件描述符信息
    struct epoll_filefd ffd;

    //所归属的 eventpoll 对象
    struct eventpoll *ep;

    //等待队列
    struct list_head pwqlist;
}

②将一个数据到达时用到的回调函数添加到socket的进程等待队列中,其回调函数是ep_poll_callback

③将epitem插入到epoll对象的红黑树里;

完事之后的数据结构如下:

3、epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)

epoll_wait首先会检查eventpoll对象的就绪链表rdlist上是否有数据到达,如果没有就把当前的进程描述符添加到eventpoll的等待队列里,然后把自己阻塞掉就完事。

  • epoll处理到达数据

前面epoll_ctl函数执行时,内核为每一个socket上都添加了一个等待队列。在epoll_wait运行完的时候,又在eventpoll对象上添加了等待队列元素。目前结构图如下:

数据到达的处理流程如下:

①socket的数据接收队列有数据到达时,会通过进程等待队列的回调函数ep_poll_callback唤醒红黑树的节点epitem

②ep_poll_callback函数将有数据到达的epitem添加到eventpoll对象的就绪队列rdlist中

③ep_poll_callback函数检查eventpoll对象的进程等待队列上是否有等待项,如果有,通过default_wake_function唤醒这个进程,进行数据的处理

④当进程醒来后,继续从epoll_wait时暂停的代码继续执行,把rdlist中就绪的事件返回给用户进程,让用户进程调用recv把已经到达内核socket等待队列的数据拷贝到用户空间使用

  • 总结

在epoll相关的函数里,内核运行环境分为两部分:①用户进程内核态。进程调用epoll_wait函数时,会将进程陷入内核态来执行,这部分代码负责查看接收队列,以及负责把当前进程阻塞掉,让出CPU。②硬软中断上下文:在这些组件中将数据包从网卡接收过来进行处理,然后放到socket的接收队列。对于epoll来说,再找到socket关联的epitem,再把它添加到epoll对象的就绪链表rdlist中,这个时候再捎带检查一下epoll上是否有被阻塞的线程,如果有则唤醒之。

另外,我们可以看到wake up回调函数机制被频繁使用:

一是阻塞IO中数据到达socket的等待队列时,通过回调函数唤醒进程;

二是epoll数据到达socket数据接收队列时,通过回调函数ep_poll_callback找到eventpoll中红黑树的epitem节点,将其加入到就绪队列rdlist

三是通过回调函数default_wake_function唤醒用户进程,并将rdlist传递给用户进程,让用户进程读取数据。从中可知,这种回调机制能够定向准确的通知程序要处理的事件,而不需要每次都循环遍历查找数据是否到达,以及该由哪个进程处理,提高了程序效率。

在实践中,只要活足够多,epoll_wait根本就不会让进程阻塞,用户进程会一直干活,知道epoll_wait实在没活可干,参会主动让出CPU。这就是epoll高效的地方。

参考:https://cloud.tencent.com/developer/article/2188691

https://cloud.tencent.com/developer/article/1964472

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

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

相关文章

【零散技术】一分钟完成Odoo悬挂网站备案号

序言:时间是我们最宝贵的财富,珍惜手上的每个时分 目录 1.激活开发者模式 2.修改视图 Odoo套上域名是常见的需求,当我们兴致勃勃的做好 域名申请,网站备案,域名解析,SSL证书申请,Nginx转发后,就可以通过域…

横向移动与痕迹清理

目录 横向移动漏洞利⽤服务利⽤IPC横向计划任务横向计划任务横向WMI横向SMB横向DCOM横向WinRM横向PSEXEC横向其他⽅式横向 软件部署利⽤GPO组策略横向 密码喷洒密码策略检查喷洒主机喷洒⽤户名喷洒密码喷洒hash喷洒服务 痕迹清除OPSEC清除webshell清除隧道⼯具清除落地样本清除…

由于找不到krpt.dll,无法继续执行代码该怎么办?总结三种简单有效修复方法

1. krpt.dll 简介 1.1 定义 krpt.dll 是一个 Windows 动态链接库文件(Dynamic Link Library),这种类型的文件包含可由多个应用程序共享的函数和资源。它是Windows操作系统中的一个重要组件,对于系统的正常运行起着至关重要的作用…

模块化沙箱的功能特点

模块化沙箱是一种高灵活性和高扩展性的数据安全产品,通过选择不同的沙箱模块,满足不同的安全需求。 同时,深信达模块化沙箱,根据企事业单位各类国密标准需求,合理转换沙箱模式,满足不同场景、不同类型的数…

TK东南亚、美区、英区产品投放内容该如何选择?

TikTok是抖音在海外市场的版本,已经成为全球最受欢迎的短视频应用之一,并被视为品牌国际化的重要平台。卖家若能有效利用 TikTok,有望在全球范围内提升企业知名度和产品销量,吸引大量的粉丝和订单。那么,在不同国家&am…

每日论文13-18TCAS2数控调谐电感的V波段CMOS压控振荡器

《A V-Band CMOS VCO With Digitally-Controlled Inductor for Frequency Tuning》 18TCAS2 广东省毫米波与太赫兹重点实验室 有个手头上的东西感觉粗调电感可能会比粗调电容好一些,所以拜读一下老板18年的这篇TCAS2,这感觉是个偏理论一点的工作。 首…

哇塞!FLUX 杠上 Midjourney,你选谁?

大家和大家聊聊最近超火的 AI 绘图工具 ——Black Forest Labs 的 FLUX 和一直备受青睐的 Midjourney。 来源:blackforestlabs.ai FLUX 这套开源的文本转图像模型一经推出,就掀起了不小的波澜。好多设计同行都对它充满了好奇与期待,这无疑给…

封装、继承、抽象类

面向对象共有三个特征:封装,继承,多态。 封装 封装表现: (1)方法就是一个最基本封装体。 (2)类其实也是一个封装体。 封装的好处: (1)提高…

Jquery serialize()、serializeArray()、$.param()

param()方法 1.定义:param() 方法创建**数组或对象**的序列化表示。》》该序列化值可在进行 AJAX 请求时在 URL 查询字符串中使用。2.语法:$.param(object,trad)object:必需,规定要序列化的数组或对象。trad:可选。布尔…

如何提高LabVIEW编程效率

提高LabVIEW编程效率对开发者来说非常重要,尤其是在处理复杂项目或紧迫的开发周期时。以下是一些可以显著提升LabVIEW编程效率的技巧,从代码结构、工具使用到团队协作的多个角度进行详细分析: 1. 模块化设计 模块化设计 是提高代码可维护性和…

Linux——grep-wc-管道符

grep命令 利用关键字过滤文件行,找到关键字所在那一行 wc命令 统计文件行数,单词数量 wc命令 不带选项全选 wc -c test.txt 字节bytes数量 wc -m test.txt 字符数量 wc -l test-txt 行数 wc -w test-txt 单词数量 管道符 | 将左边命令的…

【LLM论文日更】| BGE-M3E embedding模型

论文:https://arxiv.org/pdf/2402.03216代码:GitHub - FlagOpen/FlagEmbedding: Retrieval and Retrieval-augmented LLMs机构:BAAI领域:embedding model发表: ​ 研究背景 研究问题:这篇文章要解决的问…

AI时代大厂AI项目管理学习路线

AI时代避免被裁员,大厂AI项目管理学习路线主要包括: 1、AI项目管理基础技能。 2、项目管理AI技术知识。 3、数据分析与决策。 4、AI项目管理工具。 5、AI项目管理知识扩展。 01 AI项目管理基础技能。 AI项目管理基础技能构成了项目管理的骨架&…

SQL 干货 | 使用 EXISTS 编写 SELECT 查询

基于 SQL 中的 EXISTS 运算符为我们提供了一种基于其他数据是否存在(或不存在)来检索数据的简便方法。更具体地说,它是一个逻辑运算符,用于评估子查询的结果,并返回一个布尔值,该值指示是否返回了行。尽管 …

《用comfyUI挑战全网AI图片产品实践案例》之comfyUI抠图工作流,用免费打败收费,实现素材自由

近段时间AI非常的火。目前有很多软件已经拥抱了AI,加入了AI的一些功能。像AI绘画的功能,基本上是每个大厂的软件产品都会配备。但是呢,这些功能都是要付费的。而且是按月收费或者是按年收费。整体算下来十分的不划算。所以我尝试用stable dif…

基础岛 第3关 :浦语提示词工程实践

作业 基础任务 (完成此任务即完成闯关) 背景问题&#xff1a;近期相关研究发现&#xff0c;LLM在对比浮点数字时表现不佳&#xff0c;经验证&#xff0c;internlm2-chat-1.8b (internlm2-chat-7b)也存在这一问题&#xff0c;例如认为13.8<13.11。 任务要求&#xff1a;利用…

嵌入式面试——FreeRTOS篇(五) 事件标志组

本篇为&#xff1a;FreeRTOS事件标志组篇 1、事件标志组介绍 答&#xff1a; 事件标志位&#xff1a;用一个位&#xff0c;来表示事件是否发生。 事件标志组是一组事件标志位的合集&#xff0c;可以简单的理解事件标志组&#xff0c;就是一个整数。 2、事件标志组的特点 答&am…

R包:APAlyzer从RNA-seq数据计算APA表达丰度

文章目录 介绍教程实战案例数据脚本运行 介绍 今天安利APAlyzer工具&#xff0c;它是通过RNA-seq数据获取3′UTR APA, intronic APA等表达谱的R包。 APAlyzer将bam文件比对到PolyA-DB数据库识别APA。 Most eukaryotic genes produce alternative polyadenylation (APA) isofo…

App推广新利器:Xinstall带你直达指定页面

在移动互联网时代&#xff0c;App的推广与运营对于企业的发展至关重要。然而&#xff0c;如何让用户在推广过程中更便捷地访问到App内的指定页面&#xff0c;一直是困扰开发者和运营者的难题。今天&#xff0c;我们就来介绍一款名为Xinstall的SDK&#xff0c;它能帮助你轻松实现…

Python中10个让你代码更安全的网络请求处理技巧

对Python感兴趣&#xff0c;想要有更深入了解的朋友可以试试我的这份学习方法和资料&#xff0c;​​​​​点这里免费获取 引言 在 Python 网络编程中&#xff0c;使用 requests 库进行 HTTP 请求是一种常见且高效的方式。该库不仅提供了简洁易用的 API&#xff0c;还支持多…