Version: Next

I/O 多路复用

思路递进:

  1. 什么是 BIO、什么是 NIO (同步阻塞、同步非阻塞;BIO 面向流,NIO 面向 Buffer 或者说 Channel)
  2. BIO 的缺陷(没连接、没数据都阻塞)、NIO 如何试图解决 BIO 的缺陷,简单的 NIO 有何不足(不停的轮询所有连接、不管有没有数据;读写操作引发用户态、内核态切换)
  3. NIO + 多路复用器(socket 在 linux 中有对应的 文件描述符 fd,多路复用器用来一次获知哪些 fd 可写可读哪些不能)
  4. Linux 多路复用器的三种实现 select、poll、epoll、原理、各自优缺点
    1. Select:用户态:将 已连接 socket 的 fd 集合拷贝到内核态,内核遍历 fd 集合标记可读可写的 socket fd(一次传输一次遍历);把 fd 集合传输会用户态,用户态再遍历 fd 集合对可读可写的 fd 进行读写操作(再次传输和再次遍历);fd 集合的长度固定 1024 bit
    2. Poll:传输 fd 没有数量限制,基于链表的动态数组,LinkedArrayList
    3. Select、poll 都要遍历 fd 集合,fd 集合需要在用户态、核心态之间传递
    4. Epoll 如何解决 select、poll 的不足
      • 数据到达网卡,积攒一定量,触发系统中断,通过 DMA 技术复制到内存,和相关 fd 绑定
      • Epoll 中的三个数据结构
        • 在内核中维护一颗 fd 红黑树
        • 从网卡到达数据相应的 fd 移动到 就绪队列 readyList,是一个 双向链表 (只在内核态操作)
        • 等待队列 里面是调用了 epoll_wait 函数的进程(当 socket 有事件发生时触发),epoll_wait 时将能读到的 fd 从 readyList 复制出去,返回给用户程序(内核态到用户态)
      • epoll_create 用来初始化 epoll
      • epoll_ctl 把 fd 添加到红黑树(从用户态拷贝到内核态)
    5. Epoll下:多个客户端连接 -> 多个 socket -> 多个 buffer -> 多个 Channel -> 一个 Selector -> 一个线程
  5. 水平触发:只要缓冲区还有内容,就返回读就绪:Select、Poll;边缘触发:只有缓冲区内容发生变化,才返回读就绪 Epoll
  6. Java 中的 Selector 对 select、poll、epoll 的封装
  7. Netty 是优秀的 NIO 框架
selectpollepoll
操作方式遍历遍历回调
底层实现数组链表红黑树
IO 效率每次调用都进行线性遍历,时间复杂度 O(n)每次调用都进行线性遍历,时间复杂度 O(n)事件触发,每当 fd 就绪,系统注册的回调函数就会被调用,将就绪 fd 存放到 readyList 双向链表,时间复杂度 O(1)
最大连接数32位机 1024
64位机 2048
无上限无上限
fd 拷贝每次调用 select 都需要把 fd 集合从用户态拷贝到内核态,再拷贝回用户态每次调用 poll 都需要把 fd 集合从用户态拷贝到内核态再拷贝回用户态调用 epoll_ctl 时拷贝进内核并保存到红黑树,之后每次 epoll_wait 不拷贝,直接查红黑树

https://zhuanlan.zhihu.com/p/150635981

https://blog.csdn.net/weixin_44273302/article/details/115269745