epoll

本质上 epoll 还是一种 I/O 多路复用技术, epoll 通过监控注册的多个描述字,来进行 I/O 事件的分发处理。不同于 poll 的是,epoll 不仅提供了默认的 level-triggered(条件触发)机制,还提供了性能更为强劲的 edge-triggered(边缘触发)机制。

epoll使用
epoll_create

epoll_create() 方法创建了一个 epoll 实例,

int epoll_create(int size);
int epoll_create(int flags);
若成功返回大于0的值,-1表示出错

参数 size 被自动忽略,但是该值仍需要一个大于 0 的整数,关于参数 size,在一开始的 epoll_create 实现中,是用来告知内核期望监控的文件描述字大小,然后内核使用这部分的信息来初始化内核数据结构,在新的实现中,这个参数不再被需要,因为内核可以动态分配需要的内核数据结构。我们只需要注意,每次将 size 设置成一个大于 0 的整数就可以了。

epoll_create1() 的用法和 epoll_create() 基本一致,如果 epoll_create1() 的输入 flags 为 0,则和 epoll_create() 一样,内核自动忽略。可以增加如 EPOLL_CLOEXEC 的额外选项。

epoll_ctl

实例增加或删除监控的事件

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
  • epfd,epoll 实例描述字,可以简单理解成是 epoll 句柄。
  • 第二个参数表示增加还是删除一个监控事件
    1. EPOLL_CTL_ADD: 向 epoll 实例注册文件描述符对应的事件;
    2. EPOLL_CTL_DEL:向 epoll 实例删除文件描述符对应的事件;
    3. EPOLL_CTL_MOD: 修改文件描述符对应的事件。
  • 第三个参数是注册的事件的文件描述符,比如一个监听套接字。
  • 第四个参数表示的是注册的事件类型,并且可以在这个结构体里设置用户需要的数据,其中最为常见的是使用联合结构里的 fd 字段,表示事件所对应的文件描述符。
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 */
 };

epoll也是基于mask事件类型

  • EPOLLIN:表示对应的文件描述字可以读;
  • EPOLLOUT:表示对应的文件描述字可以写;
  • EPOLLRDHUP:表示套接字的一端已经关闭,或者半关闭;
  • EPOLLHUP:表示对应的文件描述字被挂起;
  • EPOLLET:设置为 edge-triggered,默认为 level-triggered。
epoll_wait

调用者进程被挂起,在等待内核 I/O 事件的分发。

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
  • 第二个参数返回给用户空间需要处理的 I/O 事件,这是一个数组,数组的大小由 epoll_wait 的返回值决定,这个数组的每个元素都是一个需要待处理的 I/O 事件,其中 events 表示具体的事件类型,事件类型取值和 epoll_ctl 可设置的值一样,这个 epoll_event 结构体里的 data 值就是在 epoll_ctl 那里设置的 data,也就是用户空间和内核空间调用时需要的数据。
  • 第三个参数是一个大于 0 的整数,表示 epoll_wait 可以返回的最大事件值。
  • timeout:是 epoll_wait 阻塞调用的超时值,如果这个值设置为 -1,表示不超时;如果设置为 0 则立即返回,即使没有任何 I/O 事件发生。
条件触发和边缘触发

边缘触发。开启这个服务器程序,用 telnet 连接上,输入一些字符,服务器端只从 epoll_wait 中苏醒过一次,就是第一次有数据可读的时候。

条件触发。然后按照同样的步骤来一次,观察服务器端,服务器端不断地从 epoll_wait 中苏醒,告诉我们有数据需要读取。

$./epoll03
epoll_wait wakeup
epoll_wait wakeup
get event on socket fd == 5
epoll_wait wakeup
get event on socket fd == 5
epoll_wait wakeup
get event on socket fd == 5
epoll_wait wakeup
get event on socket fd == 5
...

这就是两者的区别,条件触发的意思是只要满足事件的条件,比如有数据需要读,就一直不断地把这个事件传递给用户;而边缘触发的意思是只有第一次满足条件的时候才触发,之后就不会再传递同样的事件了。

总结

epoll设计,避免了用户态 - 内核态的数据拷贝,提高性能。条件触发是每次用户需要读取数据时,就不停的吧这个事件传送给用户,而边缘触发,只有第一次才会触发,之后不会传递相同的事件了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值