美文网首页静心学习之路系列
静心学习之路(2)——select、poll和epoll

静心学习之路(2)——select、poll和epoll

作者: 游学者夏纳 | 来源:发表于2020-11-02 16:24 被阅读0次

    情景

    I/O复用,使程序能够监听多个文件描述符。再具体一点的情景:

    • 客户端要同时处理多个socket,比如非阻塞connect技术
    • 客户端要同时处理用户输入和网络连接,比如聊天室系统
    • TCP服务器要同时处理监听socket和连接socket,这是IO复用使用最多的场合。
    • 服务器要同时处理TCP请求和UDP请求。
    • 服务器要同时监听多个端口,处理多种服务。比如xinetd

    select API

    1.轮询,时间复杂度O(n)
    2.有连接数限制 FD_SETSIZE
    3.内核需要将消息传递到用户空间,都需要内核拷贝动作
    4.因为每次调用时都会对连接进行线性遍历,所以随着FD的增加会造成遍历速度慢的“线性下降性能问题”。
    5.在连接数少而且socket都比较活跃的情况下,性能较好

    #include <sys/select.h>
    /** maxfdpl: 待测试的最大描述符的值+1,意思是0,1,2……maxfdpl-1均将被测试
        readset writeset exceptset: 待测试的描述符集,函数返回后用FD_ISSET宏来测试那些描述符已就绪
        timeout: 空指针时表示永远等待(仅有描述符就绪时才会返回),参数全为0时表示不等待(即轮询)
                不为0时表示固定等待时间,但不超过指定的秒数和微秒数  */          
    int select(int maxfdpl, fd_set * readset, fd_set *writeset, fd_set *exceptset, const struct timeval * tiomeout);
    

    poll API

    1.轮询,时间复杂度O(n)
    2.连接数限制很大(65535,即系统最大文件描述数目cat /proc/sys/fs/file-max)
    其他同select

    #include <poll.h>
    /**  fdarray: 指向描述结构体数组的第一个元素,测试条件由events决定,从revents从读取结果
          nfds: 元素个数
          timeout: INFIM表示永远等待,0表示立即返回,>0表示等待的毫秒数(通常的时钟分辨率为10ms)
    */
    int poll(struct pollfd fd[], nfds_t nfds, int timeout); 
    
    struct pollfd{
      int fd;              //文件描述符
      short events;    //请求的事件
      short revents;   //返回的事件
    };
    

    epoll API

    1.回调,时间复杂度O(1)
    2.连接数限制很大(65535,即系统最大文件描述数目cat /proc/sys/fs/file-max)
    3.epoll通过内核和用户空间共享一块内存来实现。
    4.因为epoll内核中实现是根据每个fd上的callback函数来实现的,只有活跃的socket才会主动调用callback,所以在活跃socket较少的情况下,使用epoll没有前面两者的线性下降的性能问题,但是所有socket都很活跃的情况下,可能会有性能问题。
    5.适用于连接数量多,但活动连接较少的情况。

    #include <sys/epoll.h>
    // 创建一个内核事件表,返回表fd,size无意义(历史原因,>0即可)
    int epoll_create(int size);
    // op: 3种操作类型,在事件表上注册fd事件,以及修改和删除
    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
    // 调用类似poll,maxevents指定最多监听多少个事件,必须大于0
    int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
    
    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 */
    };
    

    LT和ET模式

    LT工作模式(Level Trigger,电平触发):当epoll_wait检测到事件变化并将此通知给应用程序时,应用程序可以不立即处理事件,当下一次调用epoll_wait时,epoll_wait会再次通知此事件,直到被处理。
    ET工作模式(Edge Trigger,边沿触发):同样的事件发生后,后续调用不再通知,因此应用程序必须立即处理该事件。可见ET模式降低了同一个epoll事件被重复触发的次数,因此效率更高。

    select和poll的工作模式都是LT,epoll支持ET高效模式(默认使用LT,相当于一个效率较高的poll)。使用ET模式的文件描述符应该是非阻塞的,如果是阻塞的name读或写操作会因为没有后续事件一直处于阻塞状态。

    参考资料

    《UNP卷1》第6章的第3节和第10节
    《Linux高性能服务器编程》第9章的第1节至第4节

    相关文章

      网友评论

        本文标题:静心学习之路(2)——select、poll和epoll

        本文链接:https://www.haomeiwen.com/subject/vpblpktx.html