epoll
epoll
是linux内核的可扩展I/O机制,旨在替代POSIX的select
和poll
函数,让需要大量文件操作符的程序拥有更佳的性能。
epoll接口
1 | #include <sys/epoll.h> |
epoll_create
创建一个epoll的句柄,参数size
告知内核这个epoll需要监听的I/O事件的个数。函数返回一个描述符,在使用完epoll以后,我们需要手动关闭这个描述符,否则可能导致描述符耗尽。
epoll_ctl
用来操纵epoll所监听的事件,参数op
表示这一次操作,其值:- EPOLL_CTL_ADD:注册新的事件到epoll中
- EPOLL_CTL_DEL:从epoll中删除一个事件
- EPOLL_CTL_MOD:修改之前注册的一个事件
epoll_event
是对应的描述符的事件的数据结构,其结构如下:1
2
3
4
5
6
7
8
9
10
11typedef 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 */
};epoll_event
中events是以下几个值的按位或的集合:- EPOLLIN:对应的描述符可读
- EPOLLOUT:对应的描述符可写
- EPOLLERR:对应的描述符发生错误
- EPOLLRDHUP:TCP套接字对端被关闭或者用
shutdown
函数关闭了写半部。 - EPOLLPRI:有紧急数据可读
- EPOLLHUP:对应的文件描述符被挂断
- EPOLLET:将EPOLL设为边缘触发
- EPOLLONESHOT:只监听一次事件,当事件发生之后如果还要监听则需要再次把事件注册入队列。
epoll
的工作模式有两种:- ET(edge trigger)模式:当
epoll_wait
检测到描述符事件发生并将此事件通知应用程序,应用程序必须立即处理,如果不处理,下次调用epoll_wait
时,不会再次向应用程序通知此事件。 - LT(level trigger)模式:当
epoll_wait
检测到描述符事件发生并通知此事件时,应用程序不需要立即处理,下次调用epoll_wait
时,会再次通知此事件。
ET模式很大程序上减少了epoll事件被重复触发的次数,因此效率较LT模式高。epoll工作在ET模式时必须使用非阻塞接口,以避免一个阻塞读/写操作把处理多个文件描述符的任务饿死。
epoll_wait
等待事件的发生。maxevents
参数告诉内核这次返回的事件最多有多少个,返回的事件存放在events
参数对应的数组中,timeoout
指定超时事件,若为-1则永久阻塞。
一个echo server/client的例子
服务器端
1 | #include <stdio.h> |
客户端
客户端代码我们也用epoll来实现:
1 | #include <stdio.h> |
See Also
文章内容和代码学习自IO多路复用之epoll总结