天天看点

「网络模型」堵塞IO(BIO)与非堵塞IO(NIO)「网络模型」堵塞IO(BIO)与非堵塞IO(NIO)

「网络模型」堵塞IO(BIO)与非堵塞IO(NIO)

文章目录

  • 「网络模型」堵塞IO(BIO)与非堵塞IO(NIO)
    • @[toc]
    • 一、概述
    • 二、堵塞IO(BIO)
    • 三、堵塞IO(NIO)
    • 参考

一、概述

在《UNIX网络编程》一书中,总结归纳了5种IO模型:

  • 阻塞IO(Blocking IO) (Linux下的I/O操作默认是阻塞I/O,即open和socket创建的I/O都是阻塞I/O)
  • 非阻塞IO(Nonblocking IO)(可以通过fcntl或者open时使用O_NONBLOCK参数,将fd设置为非阻塞的I/O)
  • IO多路复用(IO Multiplexing) (I/O多路复用,通常需要非阻塞I/O配合使用)
  • 信号驱动IO(Signal Driven IO) (SIGIO)
  • 异步IO(Asynchronous IO)
  • 阻塞IO

    非阻塞IO

这两个概念是

程序级别

的。主要描述的是程序请求操作系统IO操作后,如果IO资源没有准备好,那么程序该如何处理的问题: 前者等待;后者继续执行(并且使用线程一直轮询,直到有IO资源准备好了)

  • 同步IO

    非同步IO

这两个概念是

操作系统级别

的。主要描述的是操作系统在收到程序请求IO操作后,如果IO资源没有准备好,该如何响应程序的问题: 前者不响应,直到IO资源准备好以后;后者返回一个标记(好让程序和自己知道以后的数据往哪里通知),当IO资源准备好以后,再用事件机制返回给程序。

二、堵塞IO(BIO)

BIO就是: blocking IO。最容易理解、最容易实现的IO工作方式,应用程序向操作系统请求网络IO操作,这时应用程序会一直等待;另一方面,操作系统收到请求后,也会等待,直到网络上有数据传到监听端口;操作系统在收集数据后,会把数据发送给应用程序;最后应用程序受到数据,并解除等待状态。

应用程序想要去读取数据,他是无法直接去读取磁盘数据的,他需要先到内核里边去等待内核操作硬件拿到数据,这个过程就是1,是需要等待的,等到内核从磁盘上把数据加载出来之后,再把这个数据写给用户的缓存区,这个过程是2,如果是阻塞IO,那么整个过程中,用户从发起读请求开始,一直到读取到数据,都是一个阻塞状态。

「网络模型」堵塞IO(BIO)与非堵塞IO(NIO)「网络模型」堵塞IO(BIO)与非堵塞IO(NIO)

具体流程如下图:

用户去读取数据时,会去先发起recvform一个命令,去尝试从内核上加载数据,如果内核没有数据,那么用户就会等待,此时内核会去从硬件上读取数据,内核读取数据之后,会把数据拷贝到用户态,并且返回ok,整个过程,都是阻塞等待的,这就是阻塞IO

总结如下:

顾名思义,阻塞IO就是两个阶段都必须阻塞等待:

阶段一:

  • 用户进程尝试读取数据(比如网卡数据)
  • 此时数据尚未到达,内核需要等待数据
  • 此时用户进程也处于阻塞状态

阶段二:

  • 数据到达并拷贝到内核缓冲区,代表已就绪
  • 将内核数据拷贝到用户缓冲区
  • 拷贝过程中,用户进程依然阻塞等待
  • 拷贝完成,用户进程解除阻塞,处理数据

可以看到,阻塞IO模型中,用户进程在两个阶段都是阻塞状态。

「网络模型」堵塞IO(BIO)与非堵塞IO(NIO)「网络模型」堵塞IO(BIO)与非堵塞IO(NIO)

三、堵塞IO(NIO)

顾名思义,非阻塞IO的recvfrom操作会立即返回结果而不是阻塞用户进程。

阶段一:

  • 用户进程尝试读取数据(比如网卡数据)
  • 此时数据尚未到达,内核需要等待数据
  • 返回异常给用户进程
  • 用户进程拿到error后,再次尝试读取
  • 循环往复,直到数据就绪

阶段二:

  • 将内核数据拷贝到用户缓冲区
  • 拷贝过程中,用户进程依然阻塞等待
  • 拷贝完成,用户进程解除阻塞,处理数据

可以看到,非阻塞IO模型中,用户进程在第一个阶段是非阻塞,第二个阶段是阻塞状态。虽然是非阻塞,但性能并没有得到提高。而且忙等机制会导致CPU空转,CPU使用率暴增。

「网络模型」堵塞IO(BIO)与非堵塞IO(NIO)「网络模型」堵塞IO(BIO)与非堵塞IO(NIO)

参考

黑马程序员