epoll监听文件_epoll详解——从功能到内核

首先我们了解一下什么是I/O复用。I/O就是指网络中的I/O(即输入输出),多路是指多个TCP连接,复用是指一个或少量线程被重复使用。连起来理解就是,用少量的线程来处理网络上大量的TCP连接中的I/O。常见的I/O复用有以下三种:

  1. select
  2. poll
  3. epoll

为什么使用epoll?

这个问题也可以理解为epoll相比于select和poll有什么缺点。首先我们来分析一下select。

select函数声明:

#include#includeint select(int maxfdpl,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout);

函数第一个参数是被监听的描述符的最大值+1,select底层的数据结构是位数组,因此必须知道被监听的最大描述符才可以确定描述符的范围,否则就需要将整个数组遍历一遍。

函数第二、三、四个参数是被监听的事件,分别是读、写、异常事件。

函数的最后一个参数是监听的时间(NULL、0、正值)

selct缺点:

  1. 可以从函数参数列表上来看,select只能监听读、写、异常这三个事件
  2. selct监听的描述符是有最大值限制的,在Linux内核中是1024
  3. select的实现是每次将待检测的描述符放在位数组中,全部传给内核进行监听,内核监听之后会返回一个就绪描述符个数,并且修改了监听的事件值,以表示该事件就绪。内核再将修改后的数组传给用户空间。用户空间只能通过遍历所有描述符来处理就绪的描述符,之后再将描述符传给内核继续监听......很明显,这样在监听的描述符少的情况下并不影响效率,但是监听的描述符数量特别大的情况下,每次又只有少数描述符上有事件就绪,大量的换入换出会使得效率十分低下

第二步,我们接着分析一下poll

poll函数声明:

int poll(struct pollfd fdarray[],unsigned long nfds,int timeout);struct pollfd{    int fd;    short events;    short revents;};

第一个参数是个结构体数组,结构体中声明了被监听描述符和相应的事件,每个被监听的描述符对应一个结构体,数组表示可以监听多个描述符。

第二个参数是被监听描述符的个数。

第三个参数同select,只监听时间

poll缺点:

从函数参数来看,poll解决了select前两个问题,监听的描述符数量没有严格限制,监听的事件不止读、写、异常,但是第三个缺点依然存在,存在大量的换入换出。

在Linux2.4及以前的版本中使用的是select和poll,在2.6的时候使用的是epoll,正是因为epoll解决了select和poll共同存在的问题。接下来我们看一下epoll是怎么解决的。

epoll的相关函数

#include  int epoll_create(int size);int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

epoll内核剖析

  • epoll_create

epoll_create的做法是创建出一个内核事件表,实际上就是创建文件,这其中包括文件描述符的分配、文件实体的分配等等,在这里我们记住文件描述符中有一个域很重要,就是:private_data域,该域才是epoll的核心,其中有内核时间表、就绪描述符队列等信息。如下图:

95a39c49ddd2f81cd43ecc8bf8156b5b.png
  • epoll_ctl

该函数主要是对内核事件表的操作,涉及插入(添加监听描述符)、删除(删除被监听的描述符)、修改(修改被监听的描述符)。主要有以下步骤:

  1. 遍历内核事件表,看该描述符是否在内核事件表中。
  2. 判断所要做的操作:插入、删除或是修改
  3. 根据操作做相应处理
5be6ce9dd730b90cd4fee5d2af032e21.png

注意:此处注意的一点是在插入的时候,对相应的描述符注册了回调函数,即当该描述符上有数据就绪时,自动调用回调函数将该描述符加入就绪队列

  • epoll_wait

在看epoll_wait之前,我们来以下内核事件表和组织就绪描述符的数据结构。内核事件表的底层数据结构是红黑树,就绪描述符的底层数据结构是链表。

epoll_wait的功能就是不断查看就绪队列中有没有描述符,如果没有就一直检查、直到超时。如果有就绪描述符,就将就绪描述符通知给用户。此处有关ET和LT模式就是在给用户空间返回就绪描述符的时候体现的。

回顾以下ET模式和LT模式:ET模式是高效模式,就绪描述符只通知用户一次,如果用户没做处理内核将不再进行通知;LT模式比较稳定,如果用户没有处理就绪的描述符,内核会不断通知。

接下来我们看一下具体是怎么实现的。当为ET模式时,上边我们提到就绪描述符是用链表组织的,因此只需将就绪部分断链发给用户,而在LT模式下,用户没有处理就绪描述符时,内核会再次将未处理的就绪描述符加入到就绪队列中重复提醒用户空间。

文末给大家分享c/c++ Linux服务器高阶知识视频资料的朋友请后台私信【架构】获取

知识点有C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等等。

e9258a0c9913fed82fbbce2c6879827a.png
5665def9d7841d3f7ef035c9e56814b8.png
表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
<p> <span style="font-size:14px;color:#E53333;">限时福利1:</span><span style="font-size:14px;">购课进答疑群专享柳峰(刘运强)老师答疑服务</span> </p> <p> <br /> </p> <p> <br /> </p> <p> <span style="font-size:14px;"></span> </p> <p> <span style="font-size:14px;color:#337FE5;"><strong>为什么需要掌握高性能的MySQL实战?</strong></span> </p> <p> <span><span style="font-size:14px;"><br /> </span></span> <span style="font-size:14px;">由于互联网产品用户量大、高并发请求场景多,因此对MySQL的性能、可用性、扩展性都提出了很高的要求。使用MySQL解决大量数据以及高并发请求已经是程序员的必备技能,也是衡量一个程序员能力和薪资的标准之一。</span> </p> <p> <br /> </p> <p> <span style="font-size:14px;">为了让大家快速系统了解高性能MySQL核心知识全貌,我为你总结了</span><span style="font-size:14px;">「高性能 MySQL 知识框架图」</span><span style="font-size:14px;">,帮你梳理学习重点,建议收藏!</span> </p> <p> <br /> </p> <p> <img alt="" src="https://img-bss.csdnimg.cn/202006031401338860.png" /> </p> <p> <br /> </p> <p> <span style="font-size:14px;color:#337FE5;"><strong>【课程设计】</strong></span> </p> <p> <span style="font-size:14px;"><br /> </span> </p> <p> <span style="font-size:14px;">课程分为四大篇章,将为你建立完整的 MySQL 知识体系,同时将重点讲解 MySQL 底层运行原理、数据库的性能调优、高并发、海量业务处理、面试解析等。</span> </p> <p> <span style="font-size:14px;"><br /> </span> </p> <p> <span style="font-size:14px;"></span> </p> <p style="text-align:justify;"> <span style="font-size:14px;"><strong>一、性能优化篇:</strong></span> </p> <p style="text-align:justify;"> <span style="font-size:14px;">主要包括经典 MySQL 问题剖析、索引底层原理和事务与锁机制。通过深入理解 MySQL 的索引结构 B+Tree ,学员能够根本上弄懂为什么有些 SQL 走索引、有些不走索引,而彻底掌握索引的使用和优化技巧,能够避开很多实战中遇的“坑”。</span> </p> <p style="text-align:justify;"> <br /> </p> <p style="text-align:justify;"> <span style="font-size:14px;"><strong>二、MySQL 8.0新特性篇:</strong></span> </p> <p style="text-align:justify;"> <span style="font-size:14px;">主要包括窗口函数和通用表表达式。企业中的许多报表统计需求,如果不采用窗口函数,用普通的 SQL 语句是很难实现的。</span> </p> <p style="text-align:justify;"> <br /> </p> <p style="text-align:justify;"> <span style="font-size:14px;"><strong>三、高性能架构篇:</strong></span> </p> <p style="text-align:justify;"> <span style="font-size:14px;">主要包括主复制和读写分离。在企业的生产环境中,很少采用单台MySQL节点的情况,因为一旦单个节点发生故障,整个系统都不可用,后果往往不堪设想,因此掌握高可用架构的实现是非常有必要的。</span> </p> <p style="text-align:justify;"> <br /> </p> <p style="text-align:justify;"> <span style="font-size:14px;"><strong>四、面试篇:</strong></span> </p> <p style="text-align:justify;"> <span style="font-size:14px;">程序员获得工作的第一步,就是高效的准备面试,面试篇主要知识点回顾总结的角度出发,结合程序员面试高频MySQL问题精讲精练,帮助程序员吊打面试官,获得心仪的工作机会。</span> </p>
©️2020 CSDN 皮肤主题: 1024 设计师:白松林 返回首页