epoll

1. epoll简介:

  epoll是Linux内核的可扩展I/O事件通知机制。于Linux 2.5.44首度登场,它设计目的旨在取代既有POSIX selectpoll系统函数,让需要大量操作文件描述符的程序得以发挥更优异的性能(举例来说:旧有的系统函数所花费的时间复杂度为O(n),epoll的时间复杂度O(log n))。epoll 实现的功能与 poll 类似,都是监听多个文件描述符上的事件。

  epoll与FreeBSD的kqueue类似,底层都是由可配置的操作系统内核对象建构而成,并以文件描述符(file descriptor)的形式呈现于用户空间。epoll 通过使用红黑树(RB-tree)搜索被监控的文件描述符(file descriptor)。

  在 epoll 实例上注册事件时,epoll 会将该事件添加到 epoll 实例的红黑树上并注册一个回调函数,当事件发生时会将事件添加到就绪链表中。

2. 方法:

  • epoll_event定义:
 struct epoll_event{
     __unit32_t events;    // epoll事件
     epoll_data_t data;     // 用户数据 
};

 

  events:描述事件类型,和poll支持的事件类型基本相同(两个额外的事件:EPOLLET和EPOLLONESHOT,高效运作的关键);

  data成员:存储用户数据;

 

  • 在内核中创建epoll实例并返回一个epoll文件描述符:
int epoll_create(int size);

  在最初的实现中,调用者通过 size 参数告知内核需要监听的文件描述符数量。如果监听的文件描述符数量超过 size, 则内核会自动扩容。

  现在 size 已经没有这种语义了,但是调用者调用时 size 依然必须大于 0,以保证后向兼容性。

 

  • 向 epfd 对应的内核epoll 实例添加、修改或删除对 fd (要操作的文件描述符)上事件 event 的监听:
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

   op 可以为 EPOLL_CTL_ADDEPOLL_CTL_MODEPOLL_CTL_DEL 分别对应的是操作类型:添加新的事件,修改文件描述符上监听的事件类型,从实例上删除一个事件。

  如果 event 的 events 属性设置了 EPOLLET flag,那么监听该事件的方式是边缘触发。

 

  • epoll_wt() 可以让内核去检测就绪的事件,并将就绪的事件放到就绪列表中并返回(只用于输出检测到就绪的事件),通过返回的事件数组做进一步的事件处理:
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

  返回:成功时返回就绪的文件描述符的个数,失败时返回-1并设置errno;

  timeout:指定epoll的超时时间,单位是毫秒。当timeout为-1是,epoll_wait调用将永远阻塞,直到某个时间发生。当timeout为0时,epoll_wait调用将立即返回。

  maxevents:指定最多监听多少个事件,必须大于0;

  events:检测到事件,将所有就绪的事件从内核事件表中复制到它的第二个参数events指向的数组中;

 

3. epoll的两种触发模式:

  使用脉冲信号来解释LT和ET可能更加贴切。Level是指信号只需要处于水平,就一直会触发;而edge则是指信号为上升沿或者下降沿时触发。

  • 水平触发 LT:
  1. LT(Level - Triggered)是epoll默认的工作方式,并且同时支持 Block 和 Nonblock Socket。在这种做法中,内核检测到一个文件描述符就绪了,然后可以对这个就绪的 fd 进行 IO 操作,如果不作任何操作,内核还是会继续通知。
  2. LT模式下的读操作:只要缓冲内容存在,就一直返回读就绪;
  3. LT模式下的写操作:只要缓冲区还不满,就一直返回写就绪。  
  • 边沿触发 ET:
  1. ET(Edge - Triggered)是高速工作方式,只支持 Nonblock socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过 epoll 检测到。然后它会假设你知道文件描述符已经就绪,就不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了。但是请注意,如果一直不对这个 fd 进行 IO 操作(从而导致它再次变成未就绪),内核不会发送更多的通知(只有最初变化时的那一次就绪通知)。 ET 模式在很大程度上减少了 epoll 事件被重复触发的次数,因此效率要比 LT 模式高。epoll 工作在 ET 模式的时候,必须使用非阻塞套接口,以避免由于一个文件描述符的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。
  2. ET模式下的读操作:当缓冲区由不可读变为可读的时候(即缓冲区由空变为不空);当有新数据到达时(即缓冲区中的待读数据变多);当缓冲区有数据可读且应用进程对相应的描述符进行EPOLL_CTL_MOD 修改EPOLLIN事件时。
  3. ET模式下的写操作:当缓冲区由不可写变为可写时。当有旧数据被发送走,即缓冲区中的内容变少的时候。当缓冲区有空间可写,且应用进程对相应的描述符进行EPOLL_CTL_MOD 修改EPOLLOUT事件时。 
posted @ 2022-05-18 22:59  Siu_Miner  阅读(66)  评论(0)    收藏  举报