欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

epoll详解

程序员文章站 2022-06-14 11:18:54
...

1.epoll的工作流程

在学习epoll的ET模式和LT模式之前,先看下epoll的工作流程。epoll最大的好处是不会随着fd数目的增长而降低效率,因为他有一个记录变化的fd的列表,不需要去轮询。
epoll的三个接口函数

  1. int epoll_creat(int size);
    创建一个epoll句柄,size是告诉内核这个监听数目一共多大,当创建好句柄后,他会占用一个fd值,在linux下如果查看/proc/pid/fd,可以看到这个fd,所以在使用完epoll之后,必须调用close()关闭,否则可能会导致fd被耗尽。注:fd是文件描述符,是进程独有的描述文件描述符表的索引,根据这个索引可以找到inode table,进而描述底层文件,fd可以指向套接字、管道等。

在调用epoll_creat()函数后,发生的事情

  • 内核会帮我们在epoll文件系统里创建一个file结点
  • 在内核cache里创建一个红黑树用于储存以后epoll传来的socket
  • 内核建立一个edlist双向链表,用于存储准备就绪的事件
  • 在epoll中的事件会与设备建立回调关系,也就是说相应的事件会调用这里的回调方法,这个回调方法在内核中叫做ep_poll_callback,他会把这样的事件放到上面的rdlist双向链表中
  1. int epoll_ctl(int epfd,int top,int fd,struct epoll_event *event);
    epoll的事件注册函数
    第一个参数是epoll_creat()的返回值。
    第二个参数表示动作,用三个宏来表示
    EPOLL_CTL_ADD:注册新的fd到epfd中;
    EPOLL_CTL_MOD:修改已经注册的fd的监听事件;
    EPOLL_CTL_DEL:从epfd删除一个fd。
    第三个参数是需要监听的fd。
    第四个参数:是告诉内核需要监听什么事,struct epoll_event结构如下:
    typedef union epoll_data{
    void *ptr;
    int fd;
    __uint32 _t u32;
    __uint64_t u64;
    }epoll_data_t;
    struct epoll_event{
    __uint32_t events;
    epoll_data_t data;
    };
    events可以是这几个宏的集合:
    EPOLLIN:表示对应的文件描述符可以读(包括对端socket正常关闭)
    EPOLLOUT:表示对应的文件描述符可以写
    EPOLLPRI:表示对应的文件描述符有紧急的数据可读
    EPOLLERR:表示对应的文件描述符发生错误
    EPOLLHUP:表示对应的文件描述符挂断
    EPOLLET:将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平出发(Level Triered)来说的
    EPOLLIONSHOTl只监听一次事件,当监听完这次事件之后,如果还要继续监听这个socket,需要再次把这个socket加入到EPOLL队列里。
  2. int epoll_wait(int epfd,struct epoll_event* events,int maxevents,int timeout);
    等待事件的产生,类似于select的调用,参数events用来从内核得到事件的集合,maxevents告之这个events有多大,这个maxevents的值不能大于创建epoll_creat()的size,参数timeout是超时时间(毫秒,0会立即返回,-1是不确定,有的说是永久阻塞)。该函数返回需要处理的时间数目,如返回0表示已经超时。

2.ET和LT

  • LT(水平触发)模式下,只要这个文件描述符还有数据可读,每次 epoll_wait都会返回它的事件,提醒用户程序去操作;

  • ET(边缘触发)模式下,在它检测到有 I/O 事件时,通过 epoll_wait 调用会得到有事件通知的文件描述符,对于每一个被通知的文件描述符,如可读,则必须将该文件描述符一直读到空,让 errno 返回 EAGAIN 为止,否则下次的 epoll_wait 不会返回余下的数据,会丢掉事件。如果ET模式不是非阻塞的,那这个一直读或一直写势必会在最后一次阻塞。
    -epoll详解

  • 采取ET的好处:
    如果采用EPOLLLT模式的话,系统中一旦有大量你不需要读写的就绪文件描述符,它们每次调用epoll_wait都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率.。而采用EPOLLET这种边缘触发模式的话,当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你!!!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符。

3.反应堆模型


参考文献1 https://blog.csdn.net/dorevers/article/details/82081672
参考文献2 https://blog.csdn.net/daaikuaichuan/article/details/83862311

相关标签: linux