一、epoll_ctl函数
1.1、函数定义
int epoll_ctl(int epfd,int op,int fd,struct epoll_event * event);
作用: 向文件描述符epfd引用的epoll实例执行控制操作(op:添加、修改或者删除)。
1.2、参数详解:
1) int epfd: epoll_create()函数返回的epoll实例的句柄。
2) int op: 需要执行的操作,添加,修改,删除。
操作类型 | 描述 |
---|---|
EPOLL_CTL_ADD | 在epoll的监视列表中添加一个文件描述符(即参数fd),指定监视的事件类型(参数event) |
EPOLL_CTL_MOD | 修改监视列表中已经存在的描述符(即参数fd)对应的监视事件类型(参数event) |
EPOLL_CTL_DEL | 将某监视列表中已经存在的描述符(即参数fd)删除,参数event传NULL |
3) int fd: 需要添加,修改,删除的socket文件描述符
4) struct epoll_event * event: 需要epoll监视的fd对应的事件类型
1.3、返回值:
成功epoll_ctl()返回0。错误返回-1。错误码error(详见第三节)会被设置。
二、struct epoll_event结构体
2.1、结构体定义
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events; /* Epoll 监视的事件类型 */
epoll_data_t data; /* 用户数据 */
};
3.2、参数解释
1) data: 用户数据
data是一个联合体类型,可以是指针,文件描述符,整形(机器字长)。这个数据传给epoll以后,epoll不会使用,只会在对应的事件触发后原样的返回给用户。实际开发中一般都是保存添加的套接字的描述符,用于当epoll事件返回时识别fd。如果有需要传其它值也可以,比如改成一个结构体或者对象的地址(可以避免一次使用套接字查找对象操作)。
2) events: 事件集合
通过位掩码的方式表示不同的事件,可以同时设置多个,通过“|” 连接,可选项如下。
事件类型 | 描述 |
---|---|
EPOLLIN | 文件描述符是否可读 |
EPOLLOUT | 文件描述符是否可写 |
EPOLLRDHUP | 对端关闭连接(被动),或者套接字处于半关闭状态(主动),这个事件会被触发。当使用边缘触发模式时,很方便写代码测试连接的对端是否关闭了连接 |
EPOLLPRI | 文件描述符是否异常 |
EPOLLERR | 文件描述符是否错误。如果文件描述符已经关闭,继续写入也会收到这个事件。这个事件用户不设置也会被上报 |
EPOLLHUP | 套接字被挂起,这个事件用户不设置也会被上报 |
EPOLLET | 设置epoll的触发模式为边缘触发模式。如果没有设置这个参数,epoll默认情况下是水平触发模式 |
EPOLLONESHOT | 设置添加的事件只触发一次,当epoll_wait(2)报告一次事件后,这个文件描述符后续所有的事件都不会再报告。只是禁用,文件描述符还在监视队列中,用户可以通过epoll_ctl()的EPOLL_CTL_MOD重新添加事件 |
三、错误码解释:
错误码ID | 解释 |
---|---|
EBADF | epfd或者fd不是一个有效的文件描述符 |
EEXIST | 当参数是EPOLL_CTL_ADD时,当添加到fd已经在epfd中时,重复添加 |
EINVAL | 1、当epfd不是一个文件描述符,或者fd是一个epfd,或者op是不支持的参数。2、设置了参数EPOLLEXCLUSIVE,却没有和其它有效的参数一起设置。3、使用参数EPOLL_CTL_MOD 时同时包含了。4、使用参数EPOLL_CTL_MOD 时,当前epfd中的fd之前已经被设置了 |
ELOOP | epoll监视队列是可以添加epoll描述符的,就是支持嵌套。当嵌套关系成环时,或者嵌套深度超过5层时,会报这个错误 |
ENOENT | 使用EPOLL_CTL_MOD 和EPOLL_CTL_DEL添加 修改时,修改的套接字却不在epoll的监视队列中 |
ENOMEM | 操作所需要的内存不够 |
ENOSPC | 当EPOLL_CTL_ADD添加时,已经超过了epoll的规格限制 |
EPERM | 添加的fd不支持epoll。比如添加的是普通文件描述符 |