epoll 是 linux 特有的 I/O 复用函数。它是把用户关心的文件描述符事件放在内核的一个事件列表中,故而,无须像select和poll一样每次调用都重复传入文件描述符或事件集。但是, epoll 需要一个额外的文件描述符,来唯一标识内核中的这个事件表。这个文件描述符由 epoll_create 函数来创建:
#include int epoll_create(int size);
size 参数现在是被忽略的,但是,为了兼容性,需要传入一个大于0的数。
epoll_ctl 函数来操作epoll的内核事件表:
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epfd是epoll_create返回的文件描述符,op指定操作类型,有如下三种:
/* Valid opcodes ( "op" parameter ) to issue to epoll_ctl(). */#define EPOLL_CTL_ADD 1 /* Add a file descriptor to the interface. */#define EPOLL_CTL_DEL 2 /* Remove a file descriptor from the interface. */#define EPOLL_CTL_MOD 3 /* Change file descriptor epoll_event structure. */
event 参数指定事件,它是 epoll_event 结构体指针,定义如下:
typedef union epoll_data { void *ptr; int fd; uint32_t u32; uint64_t u64; } epoll_data_t; struct epoll_event { uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */ };
events 是成员描述符事件类型。事件类型也定义在 sys/epoll.h 文件中
enum EPOLL_EVENTS { EPOLLIN = 0x001,#define EPOLLIN EPOLLIN EPOLLPRI = 0x002,#define EPOLLPRI EPOLLPRI EPOLLOUT = 0x004,#define EPOLLOUT EPOLLOUT EPOLLRDNORM = 0x040,#define EPOLLRDNORM EPOLLRDNORM EPOLLRDBAND = 0x080,#define EPOLLRDBAND EPOLLRDBAND EPOLLWRNORM = 0x100,#define EPOLLWRNORM EPOLLWRNORM EPOLLWRBAND = 0x200,#define EPOLLWRBAND EPOLLWRBAND EPOLLMSG = 0x400,#define EPOLLMSG EPOLLMSG EPOLLERR = 0x008,#define EPOLLERR EPOLLERR EPOLLHUP = 0x010,#define EPOLLHUP EPOLLHUP EPOLLRDHUP = 0x2000,#define EPOLLRDHUP EPOLLRDHUP EPOLLEXCLUSIVE = 1u << 28,#define EPOLLEXCLUSIVE EPOLLEXCLUSIVE EPOLLWAKEUP = 1u << 29,#define EPOLLWAKEUP EPOLLWAKEUP EPOLLONESHOT = 1u << 30,#define EPOLLONESHOT EPOLLONESHOT EPOLLET = 1u << 31#define EPOLLET EPOLLET };
data 是 epoll_data_t 联合体类型。可以用fd 表示文件描述符,或者用ptr指针指向更多的用户数据。
epoll 系列系统调用的主要接口是epoll_wait函数,它在一段超时时间内等待一组文件描述符上的事件,定义:
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
成功时,返回就绪文件描述符的个数,失败返回-1,并设置errno
其中,timeout指定超时时间,单位毫秒。-1表示永远等待直到有文件描述符就绪。
maxevents 指定最多监听多少个事件,它必须大于0
epoll_wait 函数如果检测到时间,就将事件从内核事件表中复制到第二个参数events指向的数组中。这个数组只输出epoll_wait检测到的就绪事件。
epoll 对文件描述符的操作有两种模式:LT(level trigger 电平触发)和 ET(edge trigger 边沿触发)。LT是默认的工作模式。在这种模式下,文件描述符会一直被检测到直到应用程序处理它。ET模式下,文件描述符就绪,被通知给应用程序,之后,就不再通知该同一事件了。ET模式降低了同一个epoll时间被重复触发的次数,因此效率较高。
EPOLLONESHOT事件
对于注册了EPOLLONESHOT事件的文件描述符,操作系统最多触发其上注册的一个可读、可写、异常事件,且只触发一次,除非我们使用 epoll_ctl 函数重置该文件描述符上注册的 EPOLLONESHOT 事件。这样就不会用多并发的问题。
#include #include #include #include #include #include #include #include #include #include #include