[计算机网络]网络I/O模型

news/2025/3/31 9:14:41/

欢迎来到啾啾的博客🐱。
这是一个致力于构建完善的Java程序员知识体系的博客📚,记录学习的点滴,分享工作的思考、实用的技巧,偶尔也分享一些杂谈💬。
欢迎评论交流,感谢您的阅读😄。

引言

我们非常有必要了解I/O模型,以Java微服务为例,微服务架构中的网关Gateway与共享缓存Redis的核心设计的理解都离不开网络I/O。

5种I/O模型

当一次网络请求发生时,将会按顺序经历“等待数据从远程主机到达缓冲区”和“将数据从缓冲区复制到应用程序网络地址空间”两个阶段
根据实现这两个阶段的不同方法,人们把网络I/O模型总结为两类、五种模型:两类是指同步I/O与异步I/O,五种是指在同步I/O中又划分出阻塞I/O、非阻塞I/O、多路复用I/O、信号驱动I/O四种细分模型以及异步I/O模型

这里划重点,两个阶段🌟,后续5种I/O模型差异的理解基于这两个阶段的理解。
1——“等待数据从远程主机到达缓冲区”,书中这个描述理解容易有问题,如果划分成两个阶段,这个阶段的“到达”应该是“等待数据从远程主机到达缓冲区后,经由协议处理,用户进程可以安全读取的有效数据存在与内核缓冲区”。
到达缓冲区 = 数据到达——> 协议处理 ——> 数据就绪
2——“将数据从缓冲区复制到应用程序网络地址空间”
![[Pasted image 20250327130528.png]]

根据UNIX网络编程中的分类,I/O模型分为5种。

其中,同步与异步概念如下:

  • 同步
    调用端在发出请求之后,得到结果之前必须一直等待。
    比如日常代码按顺序执行就是异步,等待前一行代码执行完成然后继续下一行代码。
  • 异步
    发出调用请求之后将立即返回,不会马上得到处理结果,结果将通过状态变化和回调来通知调用者。
    比如使用线程处理任务,主线程继续执行当前任务,这种就是异步。

阻塞和非阻塞是针对请求处理过程而言,指在收到调用请求之后,返回结果之前,当前处理线程是否会被挂起。

以UDP recvfrom(接收数据并获取发送方地址的核心函数)操作为例,五种I/O模型解释如下。

阻塞I/O (Blocking I/O)

等待两个阶段操作都完成,即等待数据到缓冲区、等待数据从缓冲区复制到到应用程序网络地址空间的操作都完成。
阻塞期间,线程会休眠,状态切换开销大。
比如Socket编程就是阻塞I/O。
![[Pasted image 20250327125156.png]]

非阻塞I/O(Non-blocking I/O)

线程定期检查(轮询)数据是否就绪(数据是否已经从完成主机到达缓冲区),减少一阶段无效等待。
非阻塞I/O轮询检查本身也会消耗CPU资源,但可以避免线程休眠,适合一些很快就能返回结果的请求。

![[Pasted image 20250327125242.png]]

需要留意的是,二阶段复制数据 copy_to_user的内存拷贝操作仍可能引起微秒级阻塞(取决于数据量大小)。

多路复用I/O(I/O Multiplexing)

单线程监控多个文件描述符。即单一线程处理多个请求,当有任意请求完成阶段一进入就绪状态,则为其执行阶段二:开始复制数据。

![[Pasted image 20250327135551.png]]

其中监控多个文件描述符细分为select、poll、kqueue等不同实现。
虽然描述是单个线程的多路复用,但是一般并发处理的设计是“线程池+多路复用”。

信号驱动I/O(Signal-driven I/O)

内核通过信号(信号处理函数)通知就绪状态。

信号驱动I/O和异步I/O的区别在于,信号驱动是通知阶段一完成,可以开始阶段二,异步则是通知阶段二完成。

![[Pasted image 20250327140641.png]]

异步I/O(Asynchronous I/O)

全流程非阻塞,内核完成所有操作后通知。
异步I/O数据到缓冲区后,不需要由调用进程主动进行缓冲区复制数据到应用程序网络地址空间的操作,而是复制完成后由操作系统向线程发送信号。

![[Pasted image 20250327141231.png]]

高并发选择

模型阻塞阶段用户参与度典型应用场景
阻塞I/O全程阻塞被动等待简单客户端程序
非阻塞I/O数据拷贝阶段主动轮询低并发实时系统
I/O多路复用select阻塞,拷贝阻塞集中管理Web服务器(Nginx)
信号驱动I/O仅拷贝阶段异步通知特殊设备监控
异步I/O无阻塞完全托管高性能服务器(Proactor模式)

在高并发场景下推荐使用I/O多路复用或异步I/O模型
相较于其他I/O模型,这两种模型没有阻塞I/O模型的休眠成本、没有非阻塞I/O模型的轮询成本、也没有信号I/O模型处理上下文切换的成本。
多路复用I/O意味着在同样的线程数下,线程池能处理更多的请求。
异步I/O相较于多路复用I/O则减少了通知处理次数,且多个请求不用等待一个线程延迟更低。

关于高并发场景,细讲还有多路复用优化、异步的io_uring高级特性,还有不同并发量级的选择策略等。
多路复用瓶颈:就绪事件>线程池处理能力任务堆积怎么办?
异步瓶颈:SQ(提交队列)环大小限制批量提交规模(Linux io_uring默认4096 entries)
……
等等,I/O还有很多很多可以学习,本篇先到此为止,感谢您的阅读。

推荐阅读

【linux内核】五大经典IO模型(原理+动图+代码详解)


http://www.ppmy.cn/news/1583752.html

相关文章

Go File容器化部署方案:本地快速搭建与无公网IP远程传输文件指南

文章目录 前言1. 安装Docker2. Go File使用演示3. 安装cpolar内网穿透4. 配置Go File公网地址5. 配置Go File固定公网地址 前言 在这个信息大爆炸的时代,谁还没遇到过这样的尴尬场面呢?当你正在办公室埋头苦干时,手机突然跳出一条紧急邮件&a…

TCP的长连接和短连接,以及它们分别适用于什么场合

TCP长连接与短连接详解 一、核心概念对比 特性长连接(Persistent Connection)短连接(Short-lived Connection)连接生命周期一次建立后长期保持,多次数据交互复用同一连接每次数据交互均需新建连接,完成后…

内网渗透-DLL和C语言加载木马

免杀进阶技术 1、DLL的定义与使用 DLL:Dynamic Link library,动态链接库,是一个无法自己运行,需要额外的命令或程序来对其接口进行调用(类方法、函数)。 (1)在DevCpp中创建一个DLL项目 (2)在dllmain.c中定义源代码函数接口 #i…

CLion配置问题解决

课程笔记 https://www.yuque.com/bigdata-caoyu/newcpp CLion 激活码不可用 https://blog.csdn.net/qq_41973721/article/details/142407716 主机名:localhost 端口号:80 不为以下设置代理:*.github.com,plugins.jetbrains.com 插件无法下…

OkHttp 的证书设置

在 Android 开发中,通过 OkHttp 自定义 SSLSocketFactory 和 X509TrustManager 可以有效增强 HTTPS 通信的安全性,防止中间人攻击(如抓包工具 Charles/Fiddler 的拦截)。以下是实现防抓包的关键技术方案: 一、Okhttp设…

在 Ubuntu 下通过 Docker 部署 Nginx 服务器

1. Docker 和 Nginx 简介以及实验环境 Docker 是一个开源的容器化平台,允许开发者将应用程序及其依赖项打包成一个轻量级的、可移植的容器。通过 Docker,开发者可以在任何支持 Docker 的环境中运行应用,从而实现一致的开发和生产环境。Docke…

什么是区块链dapp开发?它能做什么?

区块链DApp(去中心化应用)作为区块链技术的核心落地场景,正在重构数字经济的底层逻辑。其核心特征包括去中心化架构(数据存储于分布式网络节点而非中心化服务器)智能合约驱动(业务逻辑通过链上代码自动执行…

Vue实现动态数据透视表(交叉表)

需求:需要根据前端选择的横维度、竖维度、值去生成一个动态的表格,然后把交叉的值放入到对应的横维度和竖维度之下,其实就是excel里面的数据透视表功能,查询交叉语句为sql语句。 实现页面: 选择一下横维度、竖维度、值之后点击查…