底层网络IO模型

本文摘自五种IO模型

  • BIO:阻塞IO
  • NIO:非阻塞IO
  • MIO:IO多路复用
  • SIO:信号驱动IO
  • AIO:异步IO

根据冯诺依曼结构,计算机分为5个部分,分别是:运算器、控制器、存储器、输入设备、输出设备。IO描述了计算机系统与外部设备之间的通信过程。

Unix网络编程中的五种IO模型

阻塞IO——Blocking IO

img

最传统的IO模型,在读写数据的过程中会发生阻塞现象。

用户线程发出IO请求,内核先去查看数据是否就绪,如果没有就绪就会等待数据就绪,此时用户线程处于阻塞状态,交出CPU。数据就绪之后,内核将数据拷贝到用户线程,返回结果给用户线程,线程结束阻塞状态。

非阻塞IO——NoneBlocking IO

img

用户发送一个IO操作后,不需要等待,马上得到一个结果。如果结果是一个error时,就知道数据还没有准备好,于是可以再次发送IO操作。一旦内核的数据准备好了,并且再次收到了用户线程的请求,马上将数据拷贝到用户线程,然后返回。

在非阻塞IO中,用户线程需要不断的询问内核数据是否就绪,说明NIO不会交出自己的CPU时间片,一直占用。对于非阻塞IO来说,一个严重的问题就是,在while循环中需要不断去询问数据是否就绪,这样会导致CPU占用率高,因为一般情况下很少使用while循环的方式来读取数据。

  • 非阻塞式主要体现在用户进程发起recvfrom系统调用的时候,这个时候系统内核还没有接收到数据报,直接返回错误给用户进程。
  • 用户接收到消息,但是不知道什么时候数据报可达,于是开始不断轮询(polling)想系统内核发起recvfrom的系统调用。
  • 用户进程轮询发起recvfrom系统调用直到数据报可达,这个时候等待系统内核复制数据报到用户进程的缓冲区,复制完成之后返回成功提示。

IO多路复用——IO Multiplexing

img

IO多路复用中,线程首先发起select调用,询问内核数据是否准备就绪,等内核吧数据准备好了,用户线程发起read调用。read调用的过程(数据从内核空间–>用户空间)还是阻塞的。

通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者是写就绪),能通知程序进行相应的读写操作,需要select,poll,epoll配合

在多路复用IO模型中,会有一个内核线程不断的轮询多个socket的状态,只有当真正读写事件发送时,才会调用实际的IO读写操作。因为在多路复用IO模型中,只需要使用一个线程就可以管理多个socket,系统不需要建立新的进程或者线程,大大减少资源占用。

  • IO复用模式是使用select或者poll函数向系统内核发起调用,阻塞在这两个系统函数调用,而不是真正阻塞于实际的IO操作(recvfrom调用才是实际阻塞IO操作的系统调用)
  • 阻塞于select函数的调用,等待数据报套接字变为可读状态
  • 当select套接字返回可读状态的时候,就可以发起recvfrom调用把数据报复制到用户空间的缓冲区

信号驱动——signal driven IO

在信号驱动的IO模型中,用户线程发起一个IO请求操作,会给对用的socket注册一个信号函数,然后用户线程继续执行,当内核数据就绪时会发送一个信号给用户线程,用户线程接到信号后,在信号函数中调用IO读写操作来进行实际的IO请求操作。一般用于UDP中,对TCP套接字基本没用,原因是信号产生的过于频繁,并且信号的出现没有告诉我们发生了什么请求。

img

用户进程可以使用信号方式,当系统内描述符就绪时就会发送SIGNO给到用户空间,这个时候再发起recvfrom的系统调用等待返回成功提示:

  • 开启套接字的信息IO启动功能,并通过一个内置安装信号处理函数signaction系统调用,发起调用之后直接返回。
  • 其次,等待内核从网络中接收到数据报之后,向用户控件发送当前数据可达的信号给信号处理函数。
  • 信号处理函数接收到信息就发起recvfrom系统调用等待内核数据复制到用户空间的缓存区。
  • 接收到复制完成的返回成功提示后,应用进程就可以开始从网络中读取数据。

异步IO——asynchronous IO

前面的四种属于同步IO,最后一种是异步IO,因为无论是多路复用还是信号驱动模型,IO操作的第2个阶段都会引起用户线程阻塞,也就是内核进行数据拷贝的过程中都会让用户线程阻塞。

71a71eda4f0d6715d07f0a75a129e09b

  • 由POSIX规范定义,告知系统内核启动某个操作,并让内核在整个操作包含数据库等待以及数据复制古城完成之后告知用户进程数据已经准备完成。
  • 与上述的信号IO模型区别在于异步是通知我们合适IO操作完成,而信号IO是通知我们何时可以启动一个IO操作。

同步IO与异步IO

  • 同步IO: 表示应用进程发起真实的IO操作请求(recvfrom)导致进程一直处于等待状态,这时候进程被阻塞,直到IO操作完成返回成功提示
  • 异步IO: 表示应用进程发起真实的IO操作请求(recvfrom)导致进程将直接返回一个错误信息,“相当于告诉进程还没有处理好,好了会通知你”
  • 阻塞IO: 主要是体现发起IO操作请求通知内核并且内核接收到信号之后如果让进程等待,那么就是阻塞
  • 非阻塞IO: 发起IO操作请求的时候不论结果直接告诉进程“不用等待,晚点再来”,那就是非阻塞
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

请我喝杯咖啡吧~

支付宝
微信