常见的网络 I/O 模型大概有四种:

  1. 同步阻塞 IO(Blocking IO)
  2. 同步非阻塞 IO(Non-blocking IO)
  3. IO 多路复用(IO Multiplexing)
  4. 异步 IO(Asynchronous IO)

应用程序和内核

Linux 操作系统在设计上将虚拟空间划分为用户空间和内核空间,两者做了隔离是相互独立的,用户空间给应用程序使用,内核空间给内核使用。内核具有最高权限,可以访问受保护的内存空间,可以访问底层的硬件设备。而这些是应用程序所不具备的,但应用程序可以通过调用内核提供的接口来间接访问或操作。所谓的常见的 I/O 模型就是基于应用程序和内核之间的交互所提出来的。以一次网络 I/O 请求过程中的 read 操作为例,请求数据会先拷贝到系统内核的缓冲区(内核空间),再从操作系统的内核缓冲区拷贝到应用程序的地址空间(用户空间)。而从内核空间将数据拷贝到用户空间过程中,就会经历两个阶段:

  1. 等待数据准备
  2. 拷贝数据

也正因为有了这两个阶段,才提出了各种网络 I/O 模型。

同步和异步

同步和异步的概念描述的是应用程序与内核的交互方式,同步是指应用程序发起 I/O 请求后需要等待或者轮询内核 I/O 操作完成后才能继续执行;而异步是指应用程序发起 I/O 请求后仍继续执行,当内核 I/O 操作完成后会通知应用程序,或者调用应用程序注册的回调函数。

阻塞和非阻塞

阻塞和非阻塞的概念描述的是应用程序调用内核 I/O 操作的方式,阻塞是指 I/O 操作需要彻底完成后才返回到用户空间;而非阻塞是指 I/O 操作被调用后立即返回给用户一个状态值,无需等到 I/O 操作彻底完成。

举一个例子来区别几种 I/O 模型

你现在新买了一套小房子,然后呢房子是在那种社区比较封闭的,大门口有门卫守着,每个人来拜访都要在大门口让住户来过来确认领下。这种社区的房子就不像那种开放式的随便进出了,也就更“安全了”。

买完后你就告诉了你的亲朋好友 A、B、C、D 地址,这时他们可能就会来你家串门。

在社区刚建好时因为设施也不完善,没有电话通知住户,门卫室也只有一条凳子。在这种简陋的环境下为了能及时让你朋友不要干等着,你就直接来到门卫室一直等着直到有朋友过来你就领着回去招待,招待完后就赶紧又到门卫室来等着....。-- 版本1

然后你发现其实不是总有朋友会来,这样干等着中间就啥事也干不了了。聪明的你就改成每隔一段时间来门卫室看下。有一天 A、B 都来了,但是呢门卫室很小只有一个凳子,这时A先来就坐上去了等着,时不时就过来的你这时来了看到了 A 就赶紧领着A到自个家并且端茶送水好好招待。招待玩后就赶紧又跑到门卫室去看有没有新的朋友来了,之前A走后就空下了凳子,B 也就坐过去了。你来到门卫室看到B也来了,也赶紧领着 B...。就这样一直傻傻的跑来跑去。-- 版本2

这种来回跑来跑去的做法大家都受够了,这个时候物管也发现问题,对门卫室扩大升级了,放了很多凳子,也安装上了电话。这时你的 A、B、C 朋友都来了,都坐在凳子上了,门卫这时就赶紧打电话给你通知你有朋友来了。因为家里太小了,一次只能招待一个朋友。你赶到门卫室领了 A 进去,招待完就领B,接着领 C。后来你写代码多挣了点钱了把房子扩大了几倍,能同时招待几个人了。这时如果 A、B、C 都来了你就可以同时都把他们招待进来。-- 版本3

写了更多的代码后你变得富余了。给了些钱给门卫帮你做点事,你告诉门卫说:“如果我有朋友来了你就直接帮我领导我家里去就好了,领完后你给我打这个电话 xxx”。这时告诉完门卫后你就可以做其他事去了,有朋友来了你直接到家里招待好了。-- 版本4

以上4各版本分别对应4种 I/O 模型:

  1. 版本1 -- 同步阻塞 IO
  2. 版本2 -- 同步非阻塞 IO
  3. 版本3 -- IO 多路复用
  4. 版本4 -- 异步 IO

IO 多路复用

IO 多路复用也即异步阻塞模式,这里的阻塞指的是 select 函数执行时线程被阻塞的,而不是指 socket。一般在使用 I/O 多路复用模型时,socket 还是设置为 nonblock 的。

参考链接

results matching ""

    No results matching ""