当前位置:网站首页>I/O多路复用及其相关详解

I/O多路复用及其相关详解

2022-04-23 17:54:00 Augustu_

Fd详解

Fd:是一个正整型数,实际是为文件描述符表(数组)的索引,文件描述符表中保存着已打开的文件的指针。

每一个进程在PCB(Process Control Block)即进程控制块中都保存着一分文件描述符表,文件描述符就是这个表的索引,文件描述符表中每个表项都有一个指向已打开文件的指针。现在我们明确一下:已打开的文件在内核中用file结构体表示,文件描述符表中的指针指向file结构体。

file结构体才是内核中用来描述文件属性的结构体。

系统调用详解

系统调用的基本概念:通常,在操作系统中都设置了一组用于实现各种系统功能的子程序,并将它们提供给应用程序调用。

程序接口是 OS 专门为用户程序设置的,也是用户程序取得 OS 服务的唯一途径。程序接口通常是由各种类型的系统调用所组成的,因而,也可以说,系统调用提供了用户程序和操作系统之间的接口,应用程序通过系统调用实现其与 OS 的通信,并可取得它的服务

操作系统中提供了系统调用,使应用程序可以通过系统调用的方法,间接调用操作系统的相关过程,取得相应的服务

软件中断实现系统调用:

  • 软件中断:它是通过软件指令触发的中断。Linux系统内核响应软件中断,从用户态切换到内核态,执行相应的系统调用。

1.Select

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

select允许应用程序监视一组文件描述符,等待一个或者多个文件描述符成为就绪状态,从而完成I/O操作。

  • fd_set 使用数组实现,数组大小使用 FD_SETSIZE 定义,所以只能监听少于 FD_SETSIZE 数量的描述符。有三种类型的描述符类型:readset、writeset、exceptset,分别对应读、写、异常条件的描述符集合。

  • timeout 为超时参数,调用 select 会一直阻塞直到有描述符的事件到达或者等待的时间超过 timeout。

  • 成功调用返回结果大于 0,出错返回结果为 -1,超时返回结果为 0。

2.Poll

int poll(struct pollfd *fds, unsigned int nfds, int timeout);
//当timeout为-1时,poll调用将会永远阻塞,直到某个事件发生;timeout为0时,则立即返回

poll 的功能与 select 类似,也是等待一组描述符中的一个成为就绪状态。

Select与Poll比较:

  1. select默认监听的文件描述符最大是1024,但可以修改,poll则没有文件描述符的限制。
  2. poll 提供了更多的事件类型,并且对描述符的重复利用上比 select 高。

3.Epoll

/* 1.epoll采用一组函数来完成任务,而不是一个函数 2.epoll把用户关心的文件描述符上的事件放在内核里的事件表中,从而无须像select和poll每次调用都要重复传入文件描述符集或事件集 */

//创建一个指示epoll内核事件表的文件描述符,该描述符将用作其他epoll系统调用的第一个参数,size不起作用。
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);
  • epoll_ctl()用于向内核注册新的描述符或者改变某个文件描述符的状态。已注册的文件描述符在内核中会被维护在一棵红黑树上。

  • epoll比select和poll更灵活,没有文件描述符数量的限制。

  • 工作模式:

    epoll 的描述符事件有两种触发模式:LT(level trigger)和 ET(edge trigger)。

    1. LT模式

      当epoll_wait()检测fd上有事件发生并将此事件通知应用程序后,将此事会通知给进程,进程可以不立即处理该事件,当应用程序下一次调用epoll_wait()时,epoll_wait还会再次向应用程序通知此事件,直到此事件被处理。同时支持 Blocking 和 Non-Blocking。

    2. ET模式

      当epoll_wait()检测fd上有事件发生并将此事件通知应用程序后,应用程序必须立即处理该事件,因为后续epoll_wait()将不会再向应用程序通知该事件。

      只支持 No-Blocking,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。

    ET模式在很大程度上降低了epoll事件被重复触发的次数,因此ET模式效率比LT模式高。

    1. EPOLLONESHOT

      为了避免多个多个线程同时操作一个Socket,可以注册EPOLLONESHOT事件。

      我们期望的是一个socket连接在任一时刻都只被一个线程处理,通过epoll_ctl对该文件描述符注册epolloneshot事件,一个线程处理socket时,其他线程将无法处理,当该线程处理完后,需要通过epoll_ctl重置epolloneshot事件

同于异

  1. select和poll的文件描述符是在用户态加入文件描述符集合的,每次调用都需要将整个集合拷贝至内核态;而epoll的文件描述符维护在内核态,每次添加文件描述符的时候都需要执行一次系统调用。
  2. select使用线性表描述文件描述符集合,文件描述符有上限;poll用链表描述,无上限;epoll则用红黑树描述文件描述符集合,且也没有上限。
  3. select和poll需要通过遍历整个文件描述符集合,判断哪个文件描述符上有事件发生;而epoll会维护一个ready list,会将就绪事件添加至list,每次调用epol_wait的时候,仅观察list是否有数据即可。

应用场景

  1. select应用场景

    elect 的 timeout 参数精度为微秒,而 poll 和 epoll 为毫秒,因此 select 更加适用于实时性要求比较高的场景,比如核反应堆的控制。

    select 可移植性更好,几乎被所有主流平台所支持。

  2. poll应用场景

    poll 没有最大描述符数量的限制,如果平台支持并且对实时性要求不高,应该使用 poll 而不是 select。

  3. epoll应用场景

    只需要运行在 Linux 平台上,有大量的描述符需要同时轮询,并且这些连接最好是长连接,因为Epoll的文件的描述符都存在内核中,需要通过系统调用epoll_ctr来改变文件描述符状态,频繁操作会降低效率。

    需要同时监控小于 1000 个描述符,就没有必要使用 epoll,因为这个应用场景下并不能体现 epoll 的优势。

版权声明
本文为[Augustu_]所创,转载请带上原文链接,感谢
https://blog.csdn.net/guslee/article/details/124337516