【Linux | 网络I/O模型】五种网络I/O模型详解

1**、数据传输过程**

在 Linux 系统中,数据传输是通过 I/O 操作来实现的。I/O 操作是指数据从应用程序到内核,再到硬件设备(如磁盘、网络接口)的过程。 操作系统为了保护自己,设计了用户态、内核态两个状态。应用程序一般工作在用户态,当调用一些底层操作的时候(比如 IO 操作),就需要切换到内核态才可以进行。


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

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

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

2**、两组重要概念**

阻塞(Blocking)与非阻塞(Non-Blocking)

1. 阻塞
  • 定义:在阻塞模式下,当一个操作无法立即完成时,程序会被挂起,直到操作完成。这意味着在操作完成之前,程序会一直等待,不能继续执行其他任务。

  • 特性

    • 等待:阻塞调用会使调用线程等待操作完成。
    • 简单:编程模型较简单,易于理解和实现。
    • 效率:在等待期间,线程无法做其他有用的工作,可能导致资源浪费。
  • 例子

    • 文件读取 :如果应用程序调用 read() 从文件中读取数据,但文件中没有数据,线程会阻塞,直到有数据可读。
    • 网络请求:如果应用程序发起网络请求,线程会阻塞,直到收到响应。
2. 非阻塞
  • 定义:在非阻塞模式下,当一个操作无法立即完成时,程序不会被挂起,而是立即返回。程序可以继续执行其他操作,并定期检查操作是否完成。

  • 特性

    • 立即返回:非阻塞调用会立即返回,无论操作是否完成。
    • 复杂:编程模型较复杂,需要轮询或回调机制来检查操作状态。
    • 效率:可以在等待期间执行其他任务,利用 CPU 资源更高效。
  • 例子

    • 文件读取 :如果应用程序调用 read() 并且文件中没有数据,调用会立即返回,应用程序需要再次调用 read() 以获取数据。
    • 网络请求:在非阻塞网络编程中,程序发起请求后立即返回,程序通过轮询或事件机制来处理响应。

同步(Synchronous)与异步(Asynchronous)

1. 同步
  • 定义:在同步模式下,操作会按照顺序执行,后续操作必须等待前一个操作完成。程序在执行下一步之前会等待当前操作完成。

  • 特性

    • 顺序执行:操作按顺序执行,后续操作依赖于前面的操作。
    • 简单:编程模型简单,因为操作是顺序进行的。
    • 等待:在操作完成之前,程序不能执行其他任务。
  • 例子

    • 同步 I/O:应用程序发起读取文件操作,必须等到读取完成后才能继续执行其他操作。
    • 函数调用:普通函数调用会同步执行,调用者必须等待函数返回结果。
2. 异步
  • 定义:在异步模式下,操作的执行不会阻塞程序的其他操作。程序可以发起操作后继续执行其他任务,并在操作完成时得到通知(通过回调、事件或未来对象等)。

  • 特性

    • 并行执行:操作可以并行进行,程序不需要等待操作完成。
    • 复杂:编程模型复杂,需要处理回调、事件、未来对象等异步机制。
    • 效率:可以更高效地利用 CPU 资源和处理时间。
  • 例子

    • 异步 I/O:应用程序发起读取文件操作后立即返回,并可以继续执行其他任务。操作完成时,系统通过回调或事件通知应用程序。
    • 异步函数 :现代编程语言(如 JavaScript、Python)提供了异步函数(如 async/await)来处理异步操作。

总结

  • 阻塞 vs 非阻塞

    • 阻塞:操作无法立即完成时,程序会等待。
    • 非阻塞:操作无法立即完成时,程序会立即返回,并可以继续执行其他任务。
  • 同步 vs 异步

    • 同步:操作按顺序执行,后续操作等待前面的操作完成。
    • 异步:操作可以并行进行,程序不需要等待操作完成,可以在操作完成时得到通知。

3**、五种网络IO模型**

3.1**、阻塞式****IO**

阻塞 I/O 是最基本的 I/O 模型。在该模型中,当进程或线程执行 I/O 操作时,它会被"阻塞",即等待操作的完成。如果操作无法立即完成,进程或线程会停止运行,直到数据准备就绪为止。简单来说,阻塞 I/O 的执行流程是"请求操作 -> 等待完成 -> 继续执行"。

3.1.1. 阻塞 I/O 的工作流程

以网络编程中的 recv(接收数据)操作为例,阻塞 I/O 的工作过程如下:

  1. 发起系统调用 :应用程序通过系统调用(如 recv())请求从网络套接字中接收数据。

  2. 等待内核准备数据:内核检查该套接字是否有可用数据。如果没有数据可读,内核会让调用线程进入"阻塞"状态,并挂起该线程。

  3. 数据准备就绪:当网络数据到达(例如从远程主机接收到 TCP 数据包),内核将数据拷贝到内核缓冲区。

  4. 数据传输:数据准备好后,内核将数据从内核缓冲区拷贝到应用程序的用户空间缓冲区中。

  5. 返回结果recv() 调用返回,程序获得数据并继续执行。

在整个过程中,应用程序在 recv() 期间是"阻塞"的,即除非数据到达,进程无法继续执行。

想象你正在银行柜台办理业务。柜台的工作人员(即操作系统)负责处理你的请求(即 I/O 操作)。以下是如何用这个例子来理解阻塞 I/O:

  1. 排队等待:你(客户端)到银行柜台(服务器)前办理业务。柜台只有一个工作人员,且每次只能处理一个客户。

  2. 提交请求:你递交你的请求(例如取款请求)。此时,柜台工作人员需要时间来处理你的请求(如检查账户余额、准备现金等)。

  3. 阻塞等待:在处理你的请求期间,工作人员需要时间来完成工作。你(客户端)只能等待,不能继续进行其他业务。在这个等待期间,你无法离开柜台,也不能处理其他事务,只能在柜台前等待工作人员完成你的请求。

  4. 完成操作:工作人员完成你的请求后,将结果(例如现金)交给你。这时,你可以继续离开柜台,完成你的业务。

3.2**、非阻塞式****IO**

非阻塞 I/O 是一种 I/O 模型,和阻塞 I/O 相反。当应用程序发起 I/O 操作时,非阻塞 I/O 不会让程序等待数据的准备情况。如果数据没有准备好,系统立即返回一个状态,表明数据尚不可用,程序可以继续执行其他操作,而不需要一直等待。非阻塞IO往往需要程序员循环的方式反复尝试读写文件描述符。

3.2.1 非阻塞 I/O 的工作流程

仍以网络编程为例,非阻塞 I/O 的 recv 操作流程如下:

  1. 发起系统调用 :应用程序调用 recv() 请求从网络套接字接收数据。

  2. 立即返回 :如果数据未准备好,recv() 不会阻塞程序,它会立即返回并给出一个错误或状态(如 EAGAIN),表明数据不可用。程序可以继续执行其他任务,而不是在等待数据期间被挂起。

  3. 检查数据:程序可以在适当的时间再次尝试接收数据,直到数据准备完毕为止。

  4. 完成数据接收:当数据准备就绪时,程序可以成功读取数据。

想象你在一家餐厅点餐,但这家餐厅提供的是"取号等餐"的服务模式。这类似于非阻塞 I/O 的工作方式:

  1. 提交请求:你到柜台下单后,服务员给了你一个取号。此时,服务员告诉你,食物需要一段时间准备。

  2. 不需要等待:你不用一直站在柜台前等待食物的完成,而是可以拿着号码牌去做其他事情,例如找个位置坐下,刷手机、聊天等。柜台没有阻塞你,你可以继续执行其他任务。

  3. 检查状态:你可以时不时地看一下餐厅的屏幕(或者听广播)来查看自己的号有没有叫到。如果号还没到,你继续等,但不需要一直在柜台前等待。

  4. 完成操作:当你的号码被叫到时,你前去取餐,整个过程完成。

3.3**、IO多路复用**

I/O 多路复用是一种技术,用于在单个进程或线程中同时处理多个 I/O 操作。它允许程序同时监视多个 I/O 流(如多个网络套接字)的状态,并在数据准备好时进行相应的操作。这种技术可以显著提高资源利用率和程序的响应性。

3.3.1. I/O 多路复用的工作原理

I/O 多路复用的基本思想是:程序可以同时处理多个 I/O 操作,而不是每次只能处理一个 I/O 操作。它通过以下方式实现:

  1. 注册感兴趣的 I/O 流:程序向操作系统注册它感兴趣的多个 I/O 流,例如多个网络连接或文件描述符。

  2. 等待事件 :程序调用 I/O 多路复用函数(如 select()poll()epoll()kqueue()),这些函数会阻塞程序,直到至少一个注册的 I/O 流有事件发生(如数据到达)。

  3. 处理事件:操作系统通知程序哪些 I/O 流有数据准备好或发生了其他事件,程序可以对这些事件进行处理。

假设你在一个大型活动现场工作,你需要同时协调多个任务(如管理多个会议室的活动、处理多个客户的请求等)。这类似于 I/O 多路复用的工作方式:

  1. 注册任务:你登记需要处理的所有任务,例如每个会议室的活动、客户的咨询请求等。这些任务就像 I/O 流。

  2. 等待事件:你定期检查每个任务的状态,可能会通过通信工具(如对讲机、手机)等待其他人的反馈或通知。

  3. 处理任务:当你收到任务的反馈或通知时,你立即处理相关任务,例如安排会议室的设备、回答客户的问题等。你不需要等到一个任务完全完成后才开始处理下一个任务,而是可以同时处理多个任务的状态。

3.4**、信号驱动式****IO**

信号驱动式 I/O 是一种 I/O 模型,用于处理 I/O 操作时的事件通知。它依赖于操作系统发送信号来通知程序某些 I/O 事件的发生,从而避免了持续的轮询。这种方法通常用于处理异步 I/O 操作。

3.4.1 信号驱动式 I/O 的工作原理

信号驱动式 I/O 的基本流程如下:

  1. 设置信号处理 :程序首先注册一个信号处理程序(Signal Handler),该程序会处理特定的信号(如 SIGIO)。

  2. 设置 I/O 设备为信号驱动模式:程序通过系统调用将 I/O 设备(如网络套接字)设置为信号驱动模式。这样,当设备有数据准备好时,操作系统会向程序发送一个信号。

  3. 等待信号:程序处于等待状态,直到操作系统发送信号。此时,信号处理程序会被触发。

  4. 处理信号:信号处理程序被调用来处理 I/O 事件。例如,它可以读取网络数据、处理文件操作等。

想象你在家中等待快递员送货,而你知道快递员会按门铃通知你。这个场景类似于信号驱动式 I/O 的工作方式:

  1. 设置通知:你设置好门铃,知道快递员会按门铃来通知你。这个动作类似于信号驱动式 I/O 中的信号处理设置。

  2. 等待信号:你在家中做其他事情,但你随时准备好听到门铃声。这个状态类似于程序等待信号的状态。

  3. 接收信号:当快递员到达时,他按响门铃。这个动作就像操作系统发送一个信号通知程序有 I/O 事件发生。

  4. 处理信号:你听到门铃声后,去开门接收快递。这就像信号处理程序被调用来处理实际的 I/O 事件(例如读取数据)。

3.5**、异步****IO**

异步 I/O 是一种 I/O 操作模型,其中 I/O 操作的请求和处理是分开的。在这种模型中,程序发起一个 I/O 请求后,不需要等待操作完成,可以继续执行其他任务。当 I/O 操作完成时,系统会通知程序,程序可以根据通知来处理结果。这种模型可以提高程序的响应性和效率,特别是在处理大量并发 I/O 操作时。

2. 异步 I/O 的工作原理

异步 I/O 的基本流程如下:

  1. 发起 I/O 请求:程序发起一个 I/O 操作请求(如读取文件或网络数据),并提供一个回调函数或通知机制,用于处理操作完成后的结果。

  2. 继续执行其他任务:发起 I/O 请求后,程序可以继续执行其他任务,而不需要等待 I/O 操作完成。

  3. 等待通知:系统在后台处理 I/O 操作。当操作完成时,操作系统会通知程序。

  4. 处理结果:程序通过回调函数、事件通知或其他机制来处理 I/O 操作的结果。

设想你在餐厅里点餐,餐厅的工作流程类似于异步 I/O 模型:

  1. 发起请求:你向服务员点餐。这类似于程序发起 I/O 请求。服务员将你的点菜信息提交给厨房。

  2. 继续活动:你可以继续做其他事情,比如聊天、玩手机等。你不需要等待厨房准备食物的整个过程,而是可以继续享受你的时间。这就像程序在发起异步 I/O 请求后继续执行其他任务。

  3. 等待通知:厨房准备好你的食物后,服务员会来通知你。这个通知相当于 I/O 操作的完成通知。

  4. 处理结果:服务员将准备好的食物送到你的桌子上,你可以开始用餐。这就像程序处理异步 I/O 操作完成后的结果。

4**、五种网络IO模型对比**

总结比较

模型 发起 I/O 请求 等待 I/O 操作 处理结果 特点
阻塞 I/O 发起请求 阻塞等待完成 处理结果 简单易懂,但效率低
非阻塞 I/O 发起请求 立即返回(检查状态) 处理结果 轮询方式,效率较高
I/O 多路复用 发起请求 等待事件发生 处理已就绪事件 高效处理多个 I/O 操作
信号驱动式 I/O 发起请求 等待信号 处理信号 避免轮询,编程复杂
异步 I/O 发起请求 继续执行其他任务 处理结果(回调或通知) 高效处理大量并发操作
相关推荐
2301_8016730122 分钟前
8.19笔记
网络·安全
wdxylb1 小时前
云原生俱乐部-shell知识点归纳(1)
linux·云原生
飞雪20072 小时前
Alibaba Cloud Linux 3 在 Apple M 芯片 Mac 的 VMware Fusion 上部署的完整密码重置教程(二)
linux·macos·阿里云·vmware·虚拟机·aliyun·alibaba cloud
路溪非溪2 小时前
关于Linux内核中头文件问题相关总结
linux
海绵不是宝宝8174 小时前
连接远程服务器上的 jupyter notebook,解放本地电脑
服务器·jupyter·github
三坛海会大神5554 小时前
计算机网络参考模型与子网划分
网络·计算机网络
云卓SKYDROID4 小时前
无人机激光测距技术应用与挑战
网络·无人机·吊舱·高科技·云卓科技
Lovyk5 小时前
Linux 正则表达式
linux·运维
Fireworkitte6 小时前
Ubuntu、CentOS、AlmaLinux 9.5的 rc.local实现 开机启动
linux·ubuntu·centos
sword devil9006 小时前
ubuntu常见问题汇总
linux·ubuntu