linux 五种网络IO模型

基本概念

1. 内核空间和用户空间

现代操作系统用的都是虚拟存储器(即对上层应用来说,地址是连续的,但是在磁盘上不一定是连续的),一般32位的寻址空间为4G(2的32次方)。为了安全,操作系统将内存空间分为两部分,一部分为内核空间,一部分为用户空间。在linux中,将最高的1G字节(虚拟地址为 0xC0000000 到 0xFFFFFFFF),供内核使用,成为内核空间,将较低的3G字节 (从虚拟地址 0x00000000 到 0xBFFFFFFF),供各个进程使用,称为用户空间。

2. 文件描述符

文件描述符是一个用于表述指向文件的引用的抽象概念。本质上是一个索引值,指向每一个进程维护的打开文件的记录表。当程序需要操作文件时,内核会返回一个文件描述符。

linux将所有的外部设备都看做一个文件来操作,使用同一的接口,对各设备通过数据流的形式与内核交互。在网络中,每一个socket的读写也有相应的描述符,称为socketfd(socket描述符)。

3. 进程的切换和阻塞

进程是操作系统对资源和调度的基本单位,每一个进程都有一个进程描述符,保存着地址空间,文件描述符指针数组等等。

进程切换时,操作系统会将该进程当前的状态保存下来,然后恢复下一个被调度的进程的信息,比如线程栈等,这一个过程称为上下文切换,非常的消耗cpu。(为什么呢,因为操作系统要将该进程的现场保存下来,比如运行的线程现在执行到哪个指令了,寄存器中变量的值要保存下来,等等。保存好该进程的现场,则开始恢复下一个被调度进程的现场)

进程阻塞,当一个进程需要等待数据时,比如要等一个网络的数据,此时它会让出cpu,变为阻塞状态,内核将网络的数据准备好,再唤醒该进程。进程阻塞时不占用CPU资源

4. 缓存IO

缓存IO又被称为标准IO,大多数文件系统的默认IO操作都是缓存IO。在linux的标准IO中,读写操作都需要经过缓存区。
20191027-1

5. 零拷贝技术

既然讲到了缓存IO,这里简单的讲一下零拷贝技术。零拷贝技术原理就是使用一个中间的硬件充当缓冲区,该硬件可以被程序直接读写,不需要将再复制一遍到用户空间。
20191027-2

Linux的网络IO模型

网络IO实际上就是socket的读取,在操作系统中,被抽象成对文件流的操作。刚才说了操作系统处理数据,在一个read操作发生时,会经历两个阶段

  1. 等待数据准备
  2. 数据从内核空间拷贝到用户空间

对socket流而言

  1. 数据从网络传输,分组到达,暂存在内核空间中
  2. 本次的数据传输完毕,操作系统将该次的请求数据拷贝到用户空间中

网络的IO模型有如下几种:

  1. 阻塞IO(blocking IO)
  2. 非阻塞IO(non-blocking IO)
  3. 多路复用IO (multiplexing IO)
  4. 信号驱动IO (signal-driven IO)
  5. 异步IO (asynchronous IO)

1. 阻塞IO

阻塞IO是linux最简单的IO模型,所有的操作都是阻塞的。在等待数据的时候,线程进入阻塞状态,只有数据准备好的时候,线程才会继续执行后续代码。
20191027-3

2. 同步非阻塞IO

同步非阻塞IO其实跟阻塞IO很像,不过在数据等待期间不是阻塞的,需要轮询内核是否准备好。

20191027-4

3. IO多路复用

前面的两种方法都是一次获取一个连接,这样效率是很低的。linux提供了另一种IO模型--IO多路复用,可以在一次查询中获取多个已准备好的连接。

线程调用select函数,此时该线程进入阻塞状态,然后等待系统处理。

操作系统负责监视是否有连接进入可读状态,然后唤醒该线程。

线程执行recvfrom,获取多个数据就绪的连接,逐一将数据复制到用户空间,然后进行数据处理。

20191027-5

4. 信号驱动IO

上面的3种IO模型都需要进入阻塞状态,等待数据就绪,但是信号驱动IO不一样,用户进程与系统建立 sigio 信道后就继续执行,当数据就绪时,系统发送信号给该进程,之后用户进程将数据复制到用户空间,进行处理。

20191027-6

5. 异步IO

用户进程调用 aio_read 后立即返回,当数据准备就绪时,操作系统将数据复制到用户空间,然后告知进程

20191027-7

参考文章
Linux NIO 系列(01) 五种网络 IO 模型
浅析Linux中的零拷贝技术