Skip to content

五种网络IO模型

数据传输过程

操作系统为了保护自己,设计了用户态、内核态两个状态。应用程序一般工作在用户态,当调用一些底层操作的时候(比如 IO 操作),就需要切换到内核态才可以进行。

服务器从网络接收的大致流程如下:

  • 数据通过计算机网络传到网卡
  • 把网卡的数据读取到socket缓冲区
  • 把socket缓冲区读取到用户缓冲区,之后应用程序就可以使用

核心就是两次读取操作,五种网络IO 模型的不同之处也就在于这两个读取操作怎么交互

两组重要概念

阻塞/非阻塞 关注的是 用户态进程/线程的状态 ,其要访问的数据是否就绪,进程/线程是否需要等待。当前接口数据还未准备就绪时,线程是否被阻塞挂起。何为阻塞挂起?就是当前线程还处于CPU时间片当中,调用了阻塞的方法,由于数据未准备就绪,则时间片还未到就让出CPU。而非阻塞就是当前接口数据还未准备就绪时,线程不会被阻塞挂起,可以不断轮询请求接口,看看数据是否已经准备就绪。

同步/异步 关注的是 消息通信机制 。所谓同步,就是在发出一个调用时,自己需要参与等待结果的过程,则为同步。同步需要主动读写数据,在读写数据的过程中还是会阻塞。异步IO,则指出发出调用以后到数据准备完成,自己都未参与,则为异步。异步只需要关注IO操作完成的通知,并不主动读写数据,由 操作系统内核 完成数据的读写。

五种网络IO模型

阻塞式IO

应用调用recvfrom读取数据时,其系统调用直到数据包到达且被复制到应用缓冲区中或者发送错误时才返回,在此期间一直会等待,进程从调用到返回这段时间内都是被阻塞的。在内核将数据准备好之前,系统调用会一直等待。所有的套接字, 默认都是阻塞方式。

  • 应用进程向内核发起recfrom读取数据
  • 内核进行准备数据报(此时应用进程阻塞)
  • 内核将数据从内核复制到应用空间
  • 复制完成后,返回成功提示

非阻塞式IO

当应用进程发起读取数据申请时,如果内核数据没有准备好会即刻告诉应用进程,不会让应用进程在这里等待,如果内核还未将数据准备好, 系统调用仍然会直接返回, 并且返回EWOULDBLOCK错误码。非阻塞IO往往需要程序员循环的方式反复尝试读写文件描述符

  • 应用进程向内核发起recvfrom读取数据。
  • 内核数据报没有准备好,即刻返回EWOULDBLOCK错误码。
  • 应用进程再次向内核发起recvfrom读取数据。
  • 内核如果已有数据包准备好就进行下一步骤,否则还是返回错误码
  • 内核将数据拷贝到用户空间。
  • 完成后,返回成功提示

IO多路复用

由一个线程监控多个网络请求(linux系统把所有网络请求以一个文件描述符来标识),来完成数据状态询问的操作,当有数据准备就绪之后再分配对应的线程去读取数据。

  • 应用进程向内核发起recvfrom读取数据
  • 内核进行准备数据报(此时应用进程阻塞)
  • 内核倘若已有数据包准备好则通知应用线程
  • 内核将数据拷贝到用户空间
  • 完成后,返回成功提示

信号驱动式IO

信号驱动IO是在调用sigaction时候建立一个SIGIO的信号联系,当内核准备好数据之后再通过SIGIO信号通知线程,此文件描述符准备就绪;当线程收到可读信号后,此时再向内核发起recvfrom读取数据的请求,因为信号驱动IO的模型下,应用线程在发出信号监控后即可返回,不会阻塞,所以一个应用线程也可以同时监控多个文件描述符。

  • 应用进程向内核发起recvfrom读取数据
  • 内核进行准备数据报,即刻返回
  • 内核倘若已有数据包准备好则通知应用线程
  • 应用进程向内核发起recvfrom读取数据
  • 内核将数据拷贝到用户空间
  • 完成后,返回成功提示

异步IO

应用进程只需要向内核发送一个读取请求,告诉内核它要读取数据后即刻返回;内核收到请求后会建立一个信号联系,当数据准备就绪,内核会主动把数据从内核空间复制到用户空间,等所有操作都完成之后,内核会发起一个通知告诉应用进程。

  • 应用进程向内核发起recvfrom读取数据

  • 内核进行准备数据报,即刻返回

  • 内核收到后会建立一个信号联系,如果已有数据包准备好,内核将数据拷贝到用户空间

  • 完成后,返回成功提示

五种网络IO模型对比

举例说明

场景:哩哩去新华书店买《王道机试指南》

  • 如果新华书店没有,就一直等着书店有了书之后才走离开 (同步阻塞)
  • 如果新华书店没有,先离开书店;然后每天都去书店逛一次,直到书店到货了,买了就走 。(同步非阻塞)
  • 如果新华书店没有,留下电话号码;书店有货时,老板打电话通知他,他再去书店买书。(信号驱动IO同步非阻塞)
  • 如果新华书店没有,留下地址;书店有货时,老板直接把书送到家(异步非阻塞)

对应于程序:用户进程调用系统调用。 用户进程 对应哩哩, 内核 对应书店老板, 书 对应 数据 , 买书就是一个 系统调用 ,而内核拷贝数据到进程这个过程近似于老板送书到哩哩手中。