epoll的水平触发LT以及边沿触发ET的原理及使用及优缺点

简介: epoll的水平触发LT以及边沿触发ET的原理及使用及优缺点

epoll的水平触发LT以及边沿触发ET的原理及使用及优缺点

网络编程相关文章:

select、poll、epoll、多线程实现并发请求处理

epoll-reactor模型原理代码解析

Http解析实现/服务器Get请求的实现


在IO多路复用的几种方法中,select和poll只支持水平触发,而epoll支持水平触发和边缘触发两种形式,因此在并发网络编程中该如何选择哪种触发方式呢?(epoll的原理不清楚的可以看一下这篇文章link

水平触发和边缘触发的不同会影响epoll的事件通过epoll_wait函数的响应。

水平触发(LT):只要缓冲区有数据,epoll_wait就会一直被触发,直到缓冲区为空;(有数据会连续触发)

边沿触发(ET):只有所监听的事件状态改变或者有事件发生时,epoll_wait才会被触发;(有数据只触发一次)

水平触发和边沿触发怎么使用呢?

LT和ET的代码案例:

首先介绍下epoll涉及的函数

int epoll_create(int size);//创建一个监听红黑树,并且返回红黑树的根节点  失败:-1,设置errno
int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);//对该监听红黑树所做的操作
//总共三个操作可选
//EPOLL_CTL_ADD 添加fd到监听红黑树
//EPOLL_CTL_MOD 修改fd在监听红黑树上的监听事件
//EPOLL_CTL_DEL 将一个fd从监听红黑树上取下(取消监听)
int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout)//监听文件描述符

水平触发LT

int epollfd = epoll_create( 5 );//创建epoll对象,epollfd是保存文件描述符的红黑树根节点
  epoll_event event;
    event.data.fd = fd;
    event.events = EPOLLIN | EPOLLLT;//添加EPOLLLT事件
    epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);//通过epoll_ctl函数添加监听的fd

边沿触发ET

int epollfd = epoll_create( 5 );//创建epoll对象,epollfd是保存文件描述符的红黑树根节点
  epoll_event event;
    event.data.fd = fd;
    event.events = EPOLLIN | EPOLLET;//添加EPOLLET事件
    epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);//通过epoll_ctl函数添加监听的fd

使用水平触发LT或边沿触发ET的结果及处理

开始说了,不同的触发方式会影响epoll_wait函数,那该怎么处理呢?

水平触发LT

//LT
int number = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, -1 );//通过epoll_wait监听到epoll事件响应,events中会保存响应的事件队列
sockfd = events[i].data.fd;//从事件队列中取出对应的文件描述符fd
n = recv(sockfd , buff, MAXLNE, 0);//通过recv将sockfd缓冲区的数据接收进buff中

水平触发写到上面就可以实现接收数据了,当buff中接收满了时,如果sockfd中假如还有数据没传完,不用担心。水平触发LT会继续触发EPOLLIN事件,epoll_wait函数会再次响应该事件,再来继续接收数据。这就是水平触发(有数据会连续触发)的意思。

边沿触发ET

//ET
int number = epoll_wait( epollfd, events, MAX_EVENT_NUMBER, -1 );//通过epoll_wait监听到epoll事件响应,events中会保存响应的事件队列
sockfd = events[i].data.fd;//从事件队列中取出对应的文件描述符fd
m_read_idx = 0;//记录一次读数据后的位置索引
while(true) {//
   // 从buff + m_read_idx索引出开始保存数据
    n = recv(sockfd , buff + m_read_idx, MAXLNE, 0 );//通过recv将sockfd缓冲区的数据接收进buff中
    if (n == -1) {
        if( errno == EAGAIN || errno == EWOULDBLOCK ) {
            // 没有数据
            break;
        } 
    } else if (n == 0) {   // 对方关闭连接
    //close(sockfd);
    break;
    }
    m_read_idx += n;
}

可以看出边沿触发ET和水平触发在读取数据时有点不同。

因为边沿触发ET(有数据只触发一次),所以假如一次recv系统调用无法将sockfd的数据全部读完的话,水平触发不会再触发EPOLLIN事件,epoll_wait函数也不会u对这一个sockfd做出响应。所以当使用ET做触发模式时,我们通常使用while()循环来将sockfd的数据全部读出来。上面程序通过m_read_idx索引记录每次读完后的位置也是常用的方法。

水平触发和边沿触发的优缺点

水平触发LT

优点:程序简单,会完整地读取所有数据。

缺点:重复地事件触发会影响高并发服务器地性能,因为epoll监控事件涉及到系统调用,需要用户态-内核态的转换。LT消耗了大量的系统资源,影响服务器性能;

边沿触发ET

优点:每次epoll_wait只用触发一次,通过程序逻辑实现读取缓冲区的所有数据,工作效率高,大大提升了服务器性能;

缺点(没归纳出来,随便写一个):不能保证数据的完整。(这个可以通过上面提到的程序逻辑实现完整地读取数据)

边沿触发没什么缺点?那是不是用epoll就用ET边沿触发就好了?

我的理解是, YES。在日常用epoll实现并发处理,可以优先使用“边沿触发(EPOLLET)+非阻塞IO”模式。

高并发服务器边沿触发(ET) 的效率更高

因为边沿触发只在数据到来的一刻才触发,很多时候服务器在接受大量数据时会先接受数据头部(水平触发在此触发第一次,边沿触发第一次)。

接着服务器通过解析头部决定要不要接这个数据。此时,如果不接受数据,水平触发需要手动清除(水平触发当有数据时,会一直触发,直到没有数据可读),而边沿触发可以将清除工作交给一个定时的清除程序去做(只触发一次,不需要的数据可以不读),自己立刻返回。

但是如果sockfd中发送的数据较小,我一次recv就能全部读完,这样LT也不会重复触发epoll事件,和边沿触发的性能差不多,那我们为什么不用更简单的水平触发呢,当然可以使用。那其实就可以理解水平触发和边沿触发是有一个分界点,就是看sockfd的数据是小数据还是大数据。recv的BUFFER_LENGTH如果一次能接收完recv buffer中的数据,就是小数据,一次接收不完就是大数据。小数据就用水平触发,大数据就用边沿触发

但但但但是LT还在一种场景有使用,就是Nginx服务器中listenfd是用的水平触发 。(网络服务器中一般涉及两类sockfd,一种是用于监听是否有连接请求的socket,一种是用于传输数据的socket(上面讲的sockfd都是用于传输数据的))

有一些解释是listenfd用水平触发,如果多个client同时连接进来,listenfd里面积攒多个连接的话,accept一次只处理一个连接,防止漏掉连接,选择水平触发。

目录
相关文章
|
数据建模 Linux C++
linux交叉编译live555
linux交叉编译live555
579 1
|
存储 设计模式 Linux
Linux C/C++ reactor原理与实现
Linux C/C++ reactor原理与实现
537 0
路径损耗计算模型 | 带你读《大规模天线波束赋形技术原理与设计 》之二十五
本小节介绍 3D 信道的路损模型,是以 ITU 信道为基础拓展得到的。
14311 0
路径损耗计算模型  | 带你读《大规模天线波束赋形技术原理与设计 》之二十五
|
7月前
|
数据采集 前端开发 Java
职责分离的艺术:剖析主从Reactor模型如何实现极致的并发性能
Reactor单线程模型中,I/O操作由单一线程处理,但业务逻辑若同步执行会阻塞线程,影响性能。为此,引入工作者线程池模型,将非I/O任务剥离至独立线程池,提升响应速度。进一步发展为主从多线程模型:MainReactor处理连接建立,SubReactor多线程管理读写,并结合过滤器链实现数据预处理,异步编程提升并发效率。该架构职责分明、扩展性强,广泛应用于Netty等高性能框架,支持百万级并发。
339 11
|
11月前
|
算法 安全 网络安全
https 的加密过程
HTTPS通过SSL/TLS协议实现安全通信,结合非对称加密与对称加密技术。客户端与服务器协商加密套件,验证证书后生成主密钥用于后续数据加密传输,确保身份真实、数据保密与完整。
2555 0
|
数据库 C++
【数据结构进阶】红黑树超详解 + 实现(附源码)
本文深入探讨了红黑树的实现原理与特性。红黑树是一种自平衡二叉搜索树,通过节点着色(红/黑)和特定规则,确保树的高度接近平衡,从而实现高效的插入、删除和查找操作。相比AVL树,红黑树允许一定程度的不平衡,减少了旋转调整次数,提升了动态操作性能。文章详细解析了红黑树的性质、插入时的平衡调整(变色与旋转)、查找逻辑以及合法性检查,并提供了完整的C++代码实现。红黑树在操作系统和数据库中广泛应用,其设计兼顾效率与复杂性的平衡。
3658 3
|
数据处理
epoll的水平触发(LT)和边缘触发模式(ET)详解
epoll的水平触发(LT)和边缘触发模式(ET)详解
974 0
|
存储 NoSQL Linux
linux之core文件如何查看和调试
通过设置和生成 core 文件,可以在程序崩溃时获取详细的调试信息。结合 GDB 等调试工具,可以深入分析 core 文件,找到程序崩溃的具体原因,并进行相应的修复。掌握这些调试技巧,对于提高程序的稳定性和可靠性具有重要意义。
8066 6
|
关系型数据库 MySQL Java
天天使用MySQL,你知道MySQL数据库能抗多少压力吗?附(真实案例)
天天使用MySQL,你知道MySQL数据库能抗多少压力吗?附(真实案例)
3121 0
|
消息中间件 监控 NoSQL
Redis脑裂问题详解及解决方案
Redis脑裂问题是分布式系统中常见的复杂问题,合理配置Redis Sentinel、使用保护模式、采用分布式锁机制以及优化网络和客户端连接策略等措施,可以有效预防和解决脑裂问题。通过深入理解Redis脑裂问题的成因和影响,采取相应的解决方案,能够提高系统的可用性和数据一致性,保障Redis集群的稳定运行。希望本文能帮助你更好地理解和应对Redis脑裂问题。
1547 2