I/O多路复用:epoll相关接口及参数

头文件

#include <sys/epoll.h>

epoll_creat创建

int epoll_creat(int size);

返回值:返回一个epoll对象的文件描述符

size:epoll要处理事件的大致数目,最新版本无意义


epoll_ctl控制函数

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

epoll_ctl 接口是用来 维护 epoll 对象中红黑树的节点,epoll_ctl可以在红黑树中添加,删除,修改节点。

参数
  • epfd: epoll对象的文件描述符
  • op:  操作类型

EPOLL_CTL_ADD(添加)

EPOLL_CTL_MOD(修改)

EPOLL_CTL_DEL(删除)

  • fd:要添加、修改、删除的文件描述符,即需要监听的socket句柄fd
  • events:一个epoll_event*类型的指针,用于监听事件类型中event中指定的类型。该类型是告诉内核需要监听什么事的结构体(联合)

event类型如下:

           struct epoll_event {
               uint32_t     events;      /* Epoll events */
               epoll_data_t data;        /* User data variable */
           };
 
           typedef union epoll_data {
               void        *ptr;
               int          fd;
               uint32_t     u32;
               uint64_t     u64;
           } epoll_data_t;
event监听的事件
  • EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
  • EPOLLOUT:表示对应的文件描述符可以写;
  • EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
  • EPOLLERR:表示对应的文件描述符发生错误;
  • EPOLLHUP:表示对应的文件描述符被挂断;
  • EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
  • EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里
返回值

调用成功,返回0,调用失败返回-1,并设置errno错误码


epoll_wait

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

epoll_wait 操作的是内核的就绪链表。调用epoll_wait能够获取就绪队列中已经就绪的事件。

参数
  • epfd:epoll对象的文件描述符
  • events:将从就绪队列中获取到的事件信息保存进 events 数组中,上层就可以通过events中获取到事件信息判断接下来的操作,如果想要从就绪队列中取出多个文件描述符信息,则需要传进去一个event_poll类型的数组。
  • maxevents:期望获取就绪队列中的事件的个数
  • timeout:在内核阻塞为timeout秒,直到就绪队列不为空
返回值

当epoll_wait返回时,直接从内核就绪链表中取下就绪的fd数据,写入到用户态的events数组中

成功返回获取到的事件的数量,返回0,表明在timeout时间内就绪队列一直为空,返回-1表示epoll_wait发生错误,并且设置errno错误码


水平触发(level trigger LT)与边缘触发(edge trigger ET)

水平触发

在epoll中默认为水平触发,但可设置为边缘触发。

在水平触发中,如果缓冲区中一直有数据,就会一直触发回调函数将socket事件加入就绪队列。

边缘触发

只有当底层的socket文件描述符中的缓冲区出现变化的时候(缓冲区数据从无到有,从有到多),才会触发回调函数将socket的事件加入到就绪队列中。如果socket缓冲区中没有发生变化,则socket一直不会被触发,即使相对应的socket缓冲区中有数据。

如果是ET模式触发的socket,则每次都需要通过循环调用recv将事件中的socket缓冲区中的数据读取干净,如果没有将数据读取干净,那么下次socket的缓冲区没有数据就绪,那么就一直不会触发socket事件,socket事件就不会加入到就绪队列中,那么socket缓冲区剩下的数据就一直不会读取上来。

一般来讲边缘触发效率相对水平触发更高,但是在一些应用场景中水平触发有其自身优点:易维护、简单、低延迟等。


  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值