IO多路复用之select、poll、epoll

关联文章:https://www.cnblogs.com/sfzlstudy/p/15921353.html

 

why(背景)

  unix中的5种常见IO模型:

    [1] blocking IO - 阻塞IO
    [2] nonblocking IO - 非阻塞IO
    [3] IO multiplexing - IO多路复用
    [4] signal driven IO - 信号驱动IO
    [5] asynchronous IO - 异步IO
  多路复用模型,其实也是同步、阻塞式的。但是它解决了:单线程同时处理多IO请求的问题,达到了普通同步阻塞模型中,必须通过多线程才能达到这个目的。
  同时具备的优势:系统开销小。原因是:不需创建什么进程/线程,也不需要维护。
 
what:
  三者的概述:
    

 

 

  select

    原理:依赖内核进行fd(文件描述符)集合的遍历,找到有可读、写的fd返回。

    接口:int select(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout);

    接口说明:maxfdp1指定待测试的文件描述字个数;fd_set可以理解为一个集合;readset、writeset、exceptset指定要让内核测试读、写和异常条件的文件描述符集合,如果哪个不需要,就设为null;timeout内核等待一个fd就绪的最大时间。返回值,就绪的fd数量,0表示超时,-1表示出错。

    缺陷:

      1、每次select调用,都涉及fd集合的拷贝(用户态到内核态)。如果fd集合很大就会,有很大开销;

      2、每次select调用,都需要遍历fd集合,从而找到可用fd集合。如果fd集合很大就会,有很大开销;

      3、每次select调用,fd集合大小有限制(内核为了减少数据拷贝的性能损坏)。其中,这个是通过宏控制的,大小不可改变(限制为1024)

 

  poll

    原理:和select类似,依赖内核进行fd结构链表的遍历,找到有可读、写的fd返回。

    接口:int poll(struct pollfd *fds, nfds_t nfds, int timeout);

        typedef struct pollfd {
              int fd;                         // 需要被检测或选择的文件描述符
              short events;                   // 对文件描述符fd上感兴趣的事件
              short revents;                  // 文件描述符fd上当前实际发生的事件
        } pollfd_t;

     接口说明:pollfd结构体的events域是监视该文件描述符的事件掩码,由用户来设置这个域。结构体的revents域是文件描述符的操作结果事件掩码,内核在调用返回时设置这个域; nfds为fds中描述符的总数量。

    缺陷:相对select优化了传人的数组结构,改为链表。没有了最多fd数量的限制了。

 

  epoll

    原理:内核使用一个文件描述符,采用红黑色树来管理fd。fd只需要传递一次。fd就绪后,由系统的回调函数,来将fa挂在ready链表上(就绪fd链表)。

    接口:

      int epoll_create(int size);
      int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
      int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

    接口说明:  

      1、epoll_create 函数创建一个epoll句柄,参数size表明内核要监听的描述符数量。调用成功时返回一个epoll句柄描述符,失败时返回-1。

      2、epoll_ctl 函数注册要监听的事件类型。四个参数解释如下:

        epfd 表示epoll句柄;
        op 表示fd操作类型,有如下3种:
          EPOLL_CTL_ADD 注册新的fd到epfd中
          EPOLL_CTL_MOD 修改已注册的fd的监听事件
          EPOLL_CTL_DEL 从epfd中删除一个fd
        fd 是要监听的描述符;
        event 表示要监听的事件;

      3、epoll_wait 函数等待事件的就绪,成功时返回就绪的事件数目,调用失败时返回 -1,等待超时返回 0:

        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;
  
        epfd 是epoll句柄;events 表示从内核得到的就绪事件集合;maxevents 告诉内核events的大小;timeout 表示等待的超时事件

    触发类型:
      水平触发(LT):默认工作模式,即当epoll_wait检测到某描述符事件就绪并通知应用程序时,应用程序可以不立即处理该事件;下次调用epoll_wait时,会再次通知此事件。   
      边缘触发(ET): 当epoll_wait检测到某描述符事件就绪并通知应用程序时,应用程序必须立即处理该事件。如果不处理,下次调用epoll_wait时,不会再次通知此事件。
 

  

    

 

  
posted @ 2022-02-25 17:39  修心而结网  阅读(88)  评论(0编辑  收藏  举报