Featured image of post Socket 与 IO 模型

Socket 与 IO 模型

select、poll、epoll

# Socket 与 IO 模型

# 1 IO 模型

# 1.1 阻塞式 IO

应用进程被阻塞,直到数据从内核缓冲区复制到应用进程缓冲区中才返回。

应该注意到,在阻塞的过程中,其它应用进程还可以执行,因此阻塞不意味着整个操作系统都被阻塞。因为其它应用进程还可以执行,所以不消耗 CPU 时间,这种模型的 CPU 利用率会比较高。

# 1.2 非阻塞式 IO

应用进程执行系统调用之后,内核返回一个错误码。应用进程可以继续执行,但是需要不断的执行系统调用来获知 I/O 是否完成,这种方式称为轮询(polling)。

由于 CPU 要处理更多的系统调用,因此这种模型的 CPU 利用率比较低。

# 1.3 IO 复用

使用 select 或者 poll 等待数据,并且可以等待多个套接字中的任何一个变为可读。这一过程会被阻塞,当某一个套接字可读时返回,之后再使用 recvfrom 把数据从内核复制到进程中。

它可以让单个进程具有处理多个 I/O 事件的能力。又被称为 Event Driven I/O,即事件驱动 I/O。

如果一个 Web 服务器没有 I/O 复用,那么每一个 Socket 连接都需要创建一个线程去处理。如果同时有几万个连接,那么就需要创建相同数量的线程。相比于多进程和多线程技术,I/O 复用不需要进程线程创建和切换的开销,系统开销更小。

# 1.4 信号驱动 IO

应用进程使用 sigaction 系统调用,内核立即返回,应用进程可以继续执行,也就是说等待数据阶段应用进程是非阻塞的。内核在数据到达时向应用进程发送 SIGIO 信号,应用进程收到之后在信号处理程序中调用 recvfrom 将数据从内核复制到应用进程中。

相比于非阻塞式 I/O 的轮询方式,信号驱动 I/O 的 CPU 利用率更高。

# 1.5 异步 IO

应用进程执行 aio_read 系统调用会立即返回,应用进程可以继续执行,不会被阻塞,内核会在所有操作完成之后向应用进程发送信号。

异步 I/O 与信号驱动 I/O 的区别在于,异步 I/O 的信号是通知应用进程 I/O 完成,而信号驱动 I/O 的信号是通知应用进程可以开始 I/O。

# 1.6 IO 模型对比

  • 同步 IO:将数据从内核缓冲区复制到应用进程缓冲区的阶段(第二阶段),应用进程会阻塞。
  • 异步 IO:第二阶段应用进程不会阻塞。

同步 IO 包括:BIO、NIO、IO 复用和信号驱动 IO,它们的区别在第一阶段

  • BIO 会直接阻塞应用进程,直到数据从内核缓冲区复制到应用进程缓冲区。

  • NIO 采用轮询方式判断 IO 是否完成,避免阻塞。

  • 信号驱动 IO 采用 SIGIO 信号方式,避免阻塞

  • IO 多路复用使用 select/poll/epoll 等待描述符成为就绪状态,避免阻塞。

其中,NIO、信号驱动 IO 和异步 IO 在第一阶段不会阻塞。

# 2 IO 复用

# 2.1 select

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

缺点:

  • 单个进程所打开的 FD 是有限制的,通过 FD_SETSIZE 设置,默认 1024
  • 每次调用 select,都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大
  • 对 socket 扫描时是线性扫描(对所有的 fds 遍历扫描),采用轮询的方法,效率较低(高并发时)

# 2.2 poll

poll 与 select 相比,只是没有 fd 的限制,其它基本一样

缺点:

  • 每次调用 poll,都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大
  • 对 socket 扫描时是线性扫描,采用轮询的方法,效率较低(高并发时)

# 2.3 epoll

select 和 poll 速度都比较慢,每次调用都需要将全部描述符从应用进程缓冲区复制到内核缓冲区。

epoll 只需要将描述符从进程缓冲区向内核缓冲区拷贝一次,并且进程不需要通过轮询来获得事件完成的描述符。

缺点:epoll 只能工作在 linux 下

# 2.4 LT 与 ET

  • LT:LT 模式下,只要这个 fd 还有数据可读,每次 epoll_wait 都会返回它的事件,提醒用户程序去操作。
  • ET:ET 模式下,它只会提示一次,直到下次再有数据流入之前都不会再提示了,无论 fd 中是否还有数据可读。所以在 ET 模式下,read 一个 fd 的时候一定要把它的 buffer 读完,或者遇到 EAGAIN 错误。

# 2.5 select、poll、epoll 对比

selectpollepoll
数据结构bitmap数组红黑树
最大连接数1024无上限无上限
fd 拷贝每次调用 select 拷贝每次调用 poll 拷贝fd 首次调用 epoll_ctl 拷贝,每次调用 epoll_wait 不拷贝
工作效率轮询:O(n)轮询:O(n)回调:O(1)

本文转载自:https://github.com/CyC2018/CS-Notes ,用于个人复习。

Licensed under CC BY-NC-SA 4.0
本博客已稳定运行
总访客数: Loading
总访问量: Loading
发表了 73 篇文章 · 总计 323.73k

使用 Hugo 构建
主题 StackJimmy 设计
基于 v3.27.0 分支版本修改