I/O多路复用之epoll

81 篇文章 2 订阅
65 篇文章 4 订阅
文章详细介绍了epoll的系统调用,包括epoll_create、epoll_ctl和epoll_wait的使用,以及epoll的工作原理,强调了epoll如何利用红黑树优化事件注册和检测,减少数据拷贝,提高大规模并发连接下的效率。epoll采用事件回调机制,解决了select/poll在大量文件描述符时的效率问题,且没有数量限制。
摘要由CSDN通过智能技术生成

一:epoll的相关系统调用

epoll_create

int epoll_create(int size);

epoll_ctl

epoll的事件注册函数。

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

  • 它不同于select()是在监听事件时告诉内核要监听什么类型的事件, 而是在这里先注册要监听的事件类型。
  • 第一个参数是epoll_create()的返回值(epoll的句柄)。
  • 第二个参数表示动作,用三个宏来表示。
  • 第三个参数是需要监听的fd。
  • 第四个参数是告诉内核需要监听什么事。

第二个参数的取值:

  • EPOLL_CTL_ADD :注册新的fd到epfd中;
  • EPOLL_CTL_MOD :修改已经注册的fd的监听事件;
  • EPOLL_CTL_DEL :从epfd中删除一个fd;

epoll_wait

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

收集在epoll监控的事件中已经发送的事件。
参数说明:

  • 参数events是分配好的epoll_event结构体数组。
  • epoll将会把发生的事件赋值到events数组中 (events不可以是空指针,内核只负责把数据复制到这个events数组中,不会去帮助我们在用户态中分配内存)。
  • maxevents告之内核这个events有多大,这个 maxevents的值不能大于创建epoll_create()时的size。
  • 如果函数调用成功,返回对应I/O上已准备好的文件描述符数目,如返回0表示已超时, 返回小于0表示函数失败。

二:epoll的工作原理

在这里插入图片描述

当某一进程调用epoll_create方法时,Linux内核会创建一个eventpoll结构体,这个结构体中有两个成
员与epoll的使用方式密切相关。

struct eventpoll{

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

};

  1. 每一个epoll对象都有一个独立的eventpoll结构体,用于存放通过epoll_ctl方法向epoll对象中添加进来的事件。

  2. 这些事件都会挂载在红黑树中,如此,重复添加的事件就可以通过红黑树而高效的识别出来(红黑树的插入时间效率是log(n),其中n为树的高度)。

  3. 而所有添加到epoll中的事件都会与设备(网卡)驱动程序建立回调关系,也就是说,当响应的事件发生时会调用这个回调方法。这个回调方法在内核中叫ep_poll_callback,它会将发生的事件添加到rdlist双链表中。

  4. 在epoll中,对于每一个事件,都会建立一个epitem结构体

  5. 当调用epoll_wait检查是否有事件发生时,只需要检查eventpoll对象中的rdlist双链表中是否有epitem元素即可。

  6. 如果rdlist不为空,则把发生的事件复制到用户态,同时将事件数量返回给用户. 这个操作的时间复杂度
    是O(1)。

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

三:epoll使用三部曲

  1. 调用epoll_create创建一个epoll句柄。
  2. 调用epoll_ctl, 将要监控的文件描述符进行注册。
  3. 调用epoll_wait, 等待文件描述符就绪。

四:优点

  1. epoll 在内核里使用红黑树来跟踪进程所有待检测的文件描述字把需要监控的 socket 通过 epoll_ctl() 函数加入内核中的红黑树里,红黑树是个高效的数据结构,增删改一般时间复杂度是 O(logn)。而 select/poll 内核里没有类似 epoll 红黑树这种保存所有待检测的 socket 的数据结构,所以 select/poll 每次操作时都传入整个 socket 集合给内核,而 epoll 因为在内核维护了红黑树,可以保存所有待检测的 socket ,所以只需要传入一个待检测的 socket,减少了内核和用户空间大量的数据拷贝和内存分配。
  2. epoll 使用事件驱动的机制,内核里维护了一个链表来记录就绪事件当某个 socket 有事件发生时,通过回调函数内核会将其加入到这个就绪事件列表中,当用户调用 epoll_wait() 函数时,只会返回有事件发生的文件描述符的个数,不需要像 select/poll 那样轮询扫描整个 socket 集合,大大提高了检测的效率。

总结:

  • 数据拷贝轻量:只在合适的时候调用 EPOLL_CTL_ADD 将文件描述符结构拷贝到内核中, 这个操作并不频繁(而select/poll都是每次循环都要进行拷贝)。
  • 事件回调机制:避免使用遍历, 而是使用回调函数的方式, 将就绪的文件描述符结构加入到就绪队列中, epoll_wait 返回直接访问就绪队列就知道哪些文件描述符就绪。
  • 没有数量限制:epoll 的方式即使监听的 Socket 数量越多的时候,效率不会大幅度降低,能够同时监听的 Socket 的数目也非常的多了,上限就为系统定义的进程打开的最大文件描述符个数。
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值