多路转接——epoll

前言

上一文介绍多路转接的方法之一select。select的存在大量的缺点:等待的文件描述符有上限,需要大量的遍历,需要将关心的事件用第三方数组管理起来。基于这些问题衍生出多路转接的第二个方案poll。poll的编写与select基本一致,所以就不再过多的介绍。相比之下衍生出第三种方案,epoll。epoll的编写更为简单,效率更高。下面就来详细介绍一些epoll。

认识epoll

epoll是改进版的多路转接方案,至此不再需要用户维护关心的事件。

epoll_create

int epoll_create(int size);

创建一个epoll模型,返回模型的句柄。

  1. 自从linux2.6.8之后,size参数是被忽略的.
  2. 用完之后, 必须调用close()关闭.

epoll_ctl

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

用于对epoll模型的增加、删除、修改关心事件

  1. 第一个参数是epoll_create()的返回值(epoll的句柄).
  2. 第二个参数表示动作,用三个宏来表示.
  3. 第三个参数是需要监听的fd.
  4. 第四个参数是告诉内核需要监听什么事.

常用的选项字段

  • EPOLL_CTL_ADD :注册新的fdepfd中。
  • EPOLL_CTL_MOD :修改epoll模型中的关心事件。
  • EPOLL_CTL_DEL:删除epoll模型的一个fd,也就是不关心了。
event事件
struct epoll_event 是一个结构体

struct epoll_event结构体当中存在32位事件类型,和一个data字段。

32位事件类型

  • EPOLLIN : 表示对应的文件描述符可以读 (包括对端SOCKET正常关闭)
  • EPOLLOUT : 表示对应的文件描述符可以写;
  • EPOLLET : 将EPOLL设为边缘触发(Edge Triggered)模式, 这是相对于水平触发(Level Triggered)来说的.

 epoll_wait

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
收集在timeout期间已经就绪的事件

  • 参数events是分配好的epoll_event结构体数组,内核负责把就绪的事件拷贝到events数组中,events数组是不能为空的。
  • maxevents:内核最多拷贝maxevents数量的事件到events数组中。
  • timeout:时间间隔,-1表示阻塞式读取。0表示非阻塞。5000:5秒内阻塞,5秒timeout一次。

如果函数调用成功,返回对应I/O上已准备好的文件描述符数目,如返回0表示已超时, 返回小于0表示函数失败。
 

总结一下:epoll的三个常用操作,epoll_create负责创建一个epoll模型。epoll_ctl负责增加删除修改关心的事件。epoll_wait收集就绪的事件,并拷贝到events数组中。


epoll的工作原理

当进程调用epoll_create创建一个epoll模型时,Linux内核会在OS底层创建eventpoll结构体,这个结构体包含俩个成员与epoll的使用紧密相关。

struct eventpoll{
    ....
    /*红黑树的根节点,这颗树中存储着所有添加到epoll中的需要监控的事件*/
    struct rb_root rbr;
    /*双链表中则存放着将要通过epoll_wait返回给用户的满足条件的事件*/
    struct list_head rdlist;
    ....
}

epoll模型就是红黑树+双链表!

红黑树的用处:红黑是调用epoll_ctr增加删除修改事件时,都是对红黑树的节点操作的

就绪队列:红黑树上关心的事件就绪了,就会被放到就绪队列中,拷贝数据就是从就绪队列移走数据。

描述这个过程

调用epoll_create时,会创建红黑树和就绪队列的指针。对于这个模型的管理是通过文件描述符。

当上层调用epoll_ctl添加事件时候,就会在红黑树中新增事件节点,并且在驱动层注册方法。

当底层有数据到来时,就会通知回调方法,将数据从红黑树链入到就绪队列中。

epoll_wait只需要检测就绪队列是否为空,就能做到判断是否有事件就绪,并且将事件拷贝到events中。

为什么选用红黑树,而不用哈希?
虽然哈希在查找时候非常迅速,但是哈希不方便扩容。扩容将会导致大量数据移动。

哈希冲突,拉链法O(n).。


epoll的优点

  • epoll的操作更加灵活,不要用户自己维护关心的事件数组,而是在合适的时机调用epoll_ctl添加到红黑树。
  • 文件描述符没有上限,却决与内存的上限。
  • 底层不必轮询事件就绪,而是采用回调的方式,将事件放到就绪队列。

epoll的工作模式

epoll有俩种工作模式:

  • LT水平触发Level Triggered
  • ET边缘触发Edge Triggered

处于LT模式下,只要文件符上有数据,就会一直通知。直到数据全部取走,或者从可写变为不可写。

EL模式,只有条件从不就绪到就绪或者从不可写变为可写,从少变多的时候,才通知一次。

从此看来,ET模式更加高效!

高效在哪里?

  1. ET模式只会通知一次,就必须让上层尽快将数据全部取走。就会通告接收方需要更大的缓冲区,同时PSH标志位。而接收缓冲区变大了,发送缓冲区也变大了,数据的吞吐量就会上升。发送的效率也就更高。
  2. 通知次数减少了,内核态到用户态的转化也变少了,提高了效率。
  3. 减少零碎的拷贝,一次性全取走的优势。


EL模式下为什么是非阻塞的?

EL模式只通知一次,要求程序员将数据全部取走。那么就必须循环读。循环读在最后一次读取的时候,必然会遇到阻塞。不想阻塞,就必须把事件设置为非阻塞读取。

EL模式适用:高并发,吞吐量大的场景(减少内核态的切换)

LE模式适用:对实时要求性高的场景

epoll常用于高并发服务器,博主编写的基于ET模式下的reactor供大家参考。

reactor高并发服务器

  • 36
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深度搜索

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值