epoll 笔记

epoll

epoll 是LINUX 特有的I/O 复用函数。它在使用和实现上与select、poll 有很大的差异。 epoll 使用一组函数来完成任务,而不是单个函数。

epoll 把用户关心的文件描述符上的时间放在内核里的一个事件表(红黑树)中,而无需像select和poll 那样每次调用都要重复传入文件描述符集或者事件集。

但是epoll需要一个额外的文件描述符,来唯一表示内核中的这个事件表,这个文件描述符使用epoll_create函数来创建:

int epoll_create(int size), 该函数返回文件描述符将用作其他所有epoll 系统调用的第一个参数,以指定要访问的内核事件表。

int epoll_ctl (int epfd, int op, int fd, struct epoll_even* event)

fd 参数是要操作的文件描述符,op 参数则指定操作类型,操作类型有如下三种:

  • EPOLL_CTL_ADD 往事件表中注册fd 上的事件
  • EPOLL_CTL_MOD 修改 fd 上的注册事件
  • EPOLL_CTL_DEL 删除fd 上注册事件

event 参数指定事件,他是epoll_event 结构指针类型,

epoll_event 的定义如下:

struct epoll_event {

​	__unit32_t events;  // epoll 事件

   epoll_data_t data;  // 用户数据

}

其中event成员描述事件类型,epoll 支持的时间类型和poll 基本相同, 表示epoll 支持的事件类型与poll 基本相同,表示epoll 事件类型的宏是在poll 对应的宏前加上“E”。

epoll_data_t 的定义如下:

typedef union epoll_data {

​	void* ptrl;	

​	int fd;

​	unit32_t u32;

​	unit64_t u64;

} epoll_data_t;

epoll_data_t 是一个联合体其4个成员中使用最多的是fd, 它指定事件所从属的目标文件描述符。

epoll系列系统调用的主要接口是epoll_wait 函数,它在一段超时事件内等待一组文件描述符上的事件:

#include<sys/epoll.h>

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

该函数成功时,返回就绪的文件描述符的个数,失败时返回-1并设置 errno。epoll_wait 函数如果检测到事件,就将所有就绪的事件从内核事件表中复制到他的第二个参数events 指向的数组中。这个数组值用于输出epoll_wait检测到的就绪事件,不像select 和 poll 数组参数那样,既用于传入用户注册事件,也用于输出内核检测到的就绪事件。这样就极大的提高了程序索引就绪文件描述符的效率。

int ret = epoll_wait(epollfd, events, MAX_EVENT_NUMBER, -1);

for(int i = 0; i < ret; i++){

​	int sockfd = events[i].data.fd;

​	/* sockfd 肯定就绪,直接处理 */

}

epoll 对文件描述符的操作有两种模式:LT(电平触发) 模式和 ET(边沿触发) 模式,采用了LT工作模式的文件描述符, 当成熟检测到事件发生,并将此事件同质应用程序之后,应用程序可以不立即处理该事件,这样,当应用程序下一次调用epoll_wait 时候,还会再次向应用程序同质次事件,知道事件被处理。而采用ET 工作模式的文件描述符,epoll_wait 检测到其上有事件发生,并将此事件通知应用程序后,应用程序会立即处理该事件,因为后续的epoll_wait 调用将不再向应用程序通知这一时间。可见ET模式在很大程度上降低了同一个epoll 时间被重复触发的次数,因此效率较高。

原文地址:https://www.cnblogs.com/wsl-hitsz/p/14600405.html