linux综合知识——I/O多路复用学习

1.1.3 I/O多路复用

一、概念

1、文件描述符(FD)

是一个非负整数。在linux里,所有的I/O设备都被抽象为文件这个概念,”一切皆文件“。linux中的一切资源都可以通过文件的方式访问和管理。而FD就类似文件的索引,指向某个资源,内核(kernel)利用FD来访问和管理资源。

2、多路复用
  • 多路:指多个socket网络连接;
  • 复用:指的是一个线程,使用一个线程来检查多个socket的FD的状态;

二、I/O模型的演进

1、同步阻塞(BIO)

创建socket接口,号为x,通过bind函数将接口号与端口号进行绑定,然后进行listen监听事件或者是read读事件,且会一直阻塞在该命令,直到有客户端连接或者发送数据。

  • 服务器采用单线程:某个socket阻塞,会影响其他的socket的处理

    accept 一个请求后,在 recvsend 调用阻塞时,将无法 accept 其他请求(必须等上一个请求处理 recvsend 完 )(无法处理并发)

  • 服务端采用多线程:客户端较多时,会造成资源浪费,全部的socket中可能每个时刻只有几个就绪。

    当 accept 一个请求后,开启线程进行 recv,可以完成并发处理,但随着请求数增加需要增加系统线程,大量的线程占用很大的内存空间,并且线程切换会带来很大的开销,10000个线程真正发生读写实际的线程数不会超过20%,每次accept都开一个线程也是一种资源浪费。

2、同步非阻塞(NIO)

同上建立绑定socket,listen监听或read事件;假如有客户端进行连接,则返回一个新的socket号,将新的socket号加入一个list中,然后遍历list中的元素查看有无发生read事件;如果没有客户端进行连接,则返回-1,代表没有客户端连接,再不断地循环。

优点:单个socket阻塞,不会影响到其他socket;

缺点:需要不断进行遍历进行系统调用,有一定开销。

3、I/O多路复用

服务器端采用单线程通过 select/poll/epoll 等系统调用获取 fd 列表,遍历有事件的 fd 进行 accept/recv/send ,使其能支持更多的并发连接请求。包括三种方式:select、poll、epoll。下面将逐个介绍。

所以,I/O多路复用,其核心思想是让单个线程同时去处理多个客户端连接,在对系统资源消耗比较小的情况下,去提升服务端的连接处理数量。一旦某个文件句柄就绪,就能够通知应用程序进行相应的读写操作;没有文件句柄就绪就会阻塞应用程序,交出CPU。

三、I/O多路复用的三种实现方式:

1、selcet方式

函数定义如下:
linux综合知识——I/O多路复用学习_第1张图片
从上述的select函数声明可以看出,fd_set本质是一个数组。如下:
linux综合知识——I/O多路复用学习_第2张图片

通过下面的视频可以更好的理解select:
linux综合知识——I/O多路复用学习_第3张图片
所以,select操作就是将socket是否就绪检查逻辑下沉到操作系统层面,避免了大量的系统调用。


2、poll方式

函数定义如下:
linux综合知识——I/O多路复用学习_第4张图片
poll的实现和select非常相似,只是描述fd集合的方式不同。poll只是使用pollfd结构而不是select的fd_set结构,这就解决了fds集合大小1024限制问题。(select函数与poll函数的区别是,前者底层是数组,所以有最大连接数的限制,后者是链表,无最大连接数的限制)


3、epoll方式

函数定义如下:
linux综合知识——I/O多路复用学习_第5张图片
linux综合知识——I/O多路复用学习_第6张图片
epoll函数模型主要是调用了三个函数:epoll_create() , epoll_ctl() , epoll_wait();

  • epoll_create:该函数生成一个 epoll 专用的文件描述符。
  • epoll_ctl:epoll 的事件注册函数,它不同于 select() 是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。
  • epoll_wait:等待事件的产生,收集在 epoll 监控的事件中已经发送的事件

具体的动画如下:
linux综合知识——I/O多路复用学习_第7张图片
epoll除了提供select/poll那种IO事件的水平触发(Level Triggered)外,还提供了边缘触发(Edge Triggered)。

epoll 为什么比select、poll更高效?

  1. epoll 采用红黑树管理文件描述符

从上图可以看出,epoll使用红黑树管理文件描述符,红黑树插入和删除的都是时间复杂度 O(logN),不会随着文件描述符数量增加而改变;select、poll采用数组或者链表的形式管理文件描述符,那么在遍历文件描述符时,时间复杂度会随着文件描述的增加而增加。

  1. epoll 将文件描述符添加和检测分离,减少了文件描述符拷贝的消耗

select&poll 调用时会将全部监听的 fd 从用户态空间拷贝至内核态空间并线性扫描一遍找出就绪的 fd 再返回到用户态。下次需要监听时,又需要把之前已经传递过的文件描述符再读传递进去,增加了拷贝文件的无效消耗,当文件描述很多时,性能瓶颈更加明显;而epoll只需要使用epoll_ctl添加一次,后续的检查使用epoll_wait,减少了文件拷贝的消耗。

你可能感兴趣的:(java,linux,后端)