【Linux】epoll

概述

基础概念

fd:
输入输出(input/output)的对象可以是文件(file), 网络(socket),进程之间的管道(pipe)。在linux系统中,都用文件描述符(fd)来表示。

IO事件:
* 可读事件:内核缓冲区非空,有数据可以读取
* 可写事件:内核缓冲区没满,有空闲空间可以写入

通知机制:
通知机制,就是当事件发生的时候,主动通知。通知机制的反面,就是轮询机制。

IO多路复用:
在一个操作里同时监听多个输入输出源,在其中一个或多个输入输出源可用的时候返回,然后对其的进行读写操作。

epoll的通俗解释

可以同时监控多个文件描述符fd,当某个fd有事件发生(可读/可写),则立刻通知相应程序进行操作。

基本使用

epoll_create

int epoll_create(int size);

功能:用于创建一个epoll的句柄,内核会产生一个epoll 实例数据结构并返回一个文件描述符,这个特殊的描述符就是epoll实例的句柄,后面的两个接口都以它为中心(即epfd形参)

参数说明:size是指监听的描述符个数,现在内核支持动态扩展,该值的意义仅仅是初次分配的fd个数,后面空间不够时会动态扩容。 (同时,size不要传0,会报invalid argument错误)

注意:
* 当创建完epoll句柄后,占用一个fd值,可通过终端执行ls /proc/<pid>/fd/查看该fd
* 使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。

epoll_ctl

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

功能:用于对需要监听的文件描述符(fd)执行op操作,比如将fd加入到epoll句柄。(epoll使用红黑树来管理各个fd)

参数说明:
1. epfd:是epoll_create()的返回值;
2. op:表示op操作,用三个宏来表示,分别代表添加、删除和修改对fd的监听事件:
* EPOLL_CTL_ADD(添加)
* EPOLL_CTL_DEL(删除)
* EPOLL_CTL_MOD(修改)
3. fd:需要监听的文件描述符;
4. epoll_event:需要监听的事件,struct epoll_event结构如下:

struct epoll_event {
   __uint32_t events;  /* Epoll事件 */
   epoll_data_t data;  /*用户可用数据*/
};

events可取值:(表示对应的文件描述符的操作)
* EPOLLIN :可读(包括对端SOCKET正常关闭);
* EPOLLOUT:可写;
* EPOLLERR:错误;
* EPOLLHUP:中断;
* EPOLLPRI:高优先级的可读(这里应该表示有带外数据到来);
* EPOLLET: 将EPOLL设为边缘触发模式,这是相对于水平触发来说的。
* EPOLLONESHOT:只监听一次事件,当监听完这次事件之后就不再监听该事件

epoll_wait

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

功能:阻塞等待注册的事件发生,返回事件的数目,并将触发的事件写入events数组中。

参数说明:
1. epfd:等待epfd上的io事件,最多返回maxevents个事件
2. events:用来从内核得到事件的集合,其大小应该和maxevents一致
3. maxevents:events数量,该maxevents值不能大于创建epoll_create()时的size;
4. timeout:超时时间
* timeout = -1,表示调用将一直阻塞,直到有文件描述符进入ready状态或者捕获到信号才返回;
* timeout = 0,用于非阻塞检测是否有描述符处于ready状态,不管结果怎么样,调用都立即返回;
* timeout > 0,表示调用将最多持续timeout时间,如果期间有检测对象变为ready状态或者捕获到信号则返回,否则直到超时。

返回值:该函数返回需要处理的事件数目,如返回0表示已超时。