【计算机网络】高级IO模型
高级IO模型
- 一、 理解 IO
- 二、认识五种高级 IO 模型
- 1. 阻塞 IO
- 2. 非阻塞IO
- 3. 信号驱动 IO
- 4. IO 多路转接
- 5. 异步 IO
- 三、高级 IO 重要概念
- 1. 阻塞和非阻塞
- 2. 同步通信和异步通信
- 四、非阻塞 IO
- fcntl
一、 理解 IO
当我们调用系统接口 write
、read
的时候,本质是把数据从用户层写给操作系统,也就是写入到 OS 的发送缓冲区中,或者从 OS 的接收缓冲区中读取数据,所以它们的本质也就是拷贝函数。
那么在这个过程中,调用 write
的时候只有当发送缓冲区中有足够的空间才能进行拷贝,当发送缓冲区没有空间了,此时 write
只能阻塞等待,不能继续拷贝。而调用 read
的时候,只有当接收缓冲区有数据才能进行读取拷贝,当接收缓冲区没有数据了,此时 read
也只能阻塞等待。上面就是 IO 的过程,所以,IO 的过程被分为两个部分:等待和拷贝!
所以在 IO 的过程中,要进行拷贝,必须先判断条件成立,也就是读写事件是否就绪。那么什么叫做高效的 IO 呢?就是在单位时间内,IO 过程中,等的比重越小,IO 的效率越高!
二、认识五种高级 IO 模型
1. 阻塞 IO
在内核将数据准备好之前,系统调用会一直等待。所有的套接字,默认都是阻塞方式。
阻塞IO是最常见的IO模型,过程如下:
2. 非阻塞IO
非阻塞 IO 就是,如果内核还未将数据准备好,系统调用仍然会直接返回,并且返回 EWOULDBLOCK 错误码。
非阻塞 IO 往往需要程序员循环的方式反复尝试读写文件描述符,这个过程称为轮询。这对 CPU 来说是较大的浪费,一般只有特定场景下才使用。
3. 信号驱动 IO
内核将数据准备好的时候,使用 SIGIO 信号通知应用程序进行 IO 操作。
4. IO 多路转接
IO 多路转接,虽然从流程图上看起来和阻塞 IO 类似,实际上最核心在于 IO 多路转接能够同时等待多个文件描述符的就绪状态。
5. 异步 IO
由内核在数据拷贝完成时,通知应用程序。和信号驱动 IO 的区别在于,信号驱动是告诉应用程序何时可以开始拷贝数据。
以上就是五种高级 IO 的模型的简单介绍。任何 IO 过程中,都包含两个步骤:第一是等待,第二是拷贝。而且在实际的应用场景中,等待消耗的时间往往都远远高于拷贝的时间。想要让 IO 更高效,最核心的办法就是让等待的时间尽量少。
三、高级 IO 重要概念
1. 阻塞和非阻塞
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态。
- 阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回
- 非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程
其实阻塞IO和非阻塞IO的效率是差不多的,因为 IO = 等待+拷贝,数据好了大家都要拷贝,只是非阻塞IO在等待的时候可以做其他事情,也就是它们之间等的方式不一样,非阻塞IO在进行非阻塞轮询时可以做自己其它的事情,所以这就导致非阻塞IO在效率上稍微高一点。
2. 同步通信和异步通信
同步和异步关注的是消息通信机制。
- 所谓同步IO,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了;换句话说,就是由调用者主动等待这个调用的结果。也就是参与了IO中的等待或者拷贝的过程,就是同步IO;
- 异步IO则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果;换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果;而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。也就是说,异步IO不参与IO,只是发起IO,最后拿结果就行。
四、非阻塞 IO
fcntl
我们以前学过 recv()
这样的接口,其中它的参数如下:
我们知道前三个参数是和 read()
的一模一样,而最后一个参数 flag 设为 0 默认就是阻塞等待。而我们可以将这个参数设为 MSG_DONTWAIT
,就是非阻塞IO,如下:
但是这种选项用起来不方便,更通用的做法是使用 fcntl()
接口。我们知道,文件描述符就是一个数组下标,而我们所有的网络通信、文件等等,都是读写文件描述符,而每一个文件描述符指向的都是内核中的文件对象,文件对象是有关于这个文件的 flags 的,也就是它的标记位。所以我们可以通过 fcntl()
接口来直接设置一个文件描述符的属性!其实就是设置其文件对象中的 flags 标志位,告诉内核这个指定的文件描述符要以非阻塞的方式来操作。系统接口如下:
如上,可以按照指定的 cmd 来对指定的文件描述符来进行可变参数部分的设置。
传入的 cmd 的值不同,后面追加的参数也不相同。fcntl 函数有5种功能:
- 复制一个现有的描述符(cmd=F_DUPFD)
- 获得/设置文件描述符标记(cmd=F_GETFD 或 F_SETFD)
- 获得/设置文件状态标记(cmd=F_GETFL 或 F_SETFL)
- 获得/设置异步 I/O 所有权(cmd=F_GETOWN 或 F_SETOWN)
- 获得/设置记录锁(cmd=F_GETLK,F_SETLK 或 F_SETLKW)
我们尝试将标准输入设置为非阻塞IO的形式,如下代码:
void SetNonBlock(int fd){// 获取文件状态标记位int fl = fcntl(fd, F_GETFL);if(fl < 0){perror("fcntl");return;}// 对获取到的文件状态标记位追加属性标记位fcntl(fd, F_SETFL, fl | O_NONBLOCK);cout << " set " << fd << " nonblock done " << endl;}int main(){char buffer[1024];// 设置标准输入为非阻塞IOSetNonBlock(0);while(true){cout << "Please Enter# ";ssize_t n = read(0, buffer, sizeof(buffer) - 1);if(n > 0){buffer[n - 1] = 0;cout << "echo: " << buffer << endl;}else if(n == 0){cout << "read done" << endl;break;}else{cerr << "read error, n = " << n << ", errno code: " << errno << ", errstr: " << strerror(errno) << endl;break;}}return 0;}
上面的代码其实是跑不通的,因为我们根本没有输入数据,因此 n 是小于0的,我们可以通过打印错误信息观察:
我们可以看到,错误码的描述大概意思就是临时资源不可用,因为我们在 else 中 break 了,我们应该把 break 去掉,改为 sleep(1),我们方便观察。
此时运行后我们在键盘上输入是可以直接回显的,如下:
所以,设置为非阻塞,如果底层 fd 数据没有就绪,recv/read/write/send,返回值会以出错的形式返回。所以出错就分为两种情况了,一种是真的出错了,另一种是底层没有就绪,这种情况就是返回 11 号错误码,也就是 EWOULDBLOCK. 那么我们怎么区分呢?可以通过 errno 区分!如果 errno 为 11,代表底层没就绪!所以我们对代码稍作修改,如下:
void SetNonBlock(int fd){// 获取文件状态标记位int fl = fcntl(fd, F_GETFL);if(fl < 0){perror("fcntl");return;}// 对获取到的文件状态标记位追加属性标记位fcntl(fd, F_SETFL, fl | O_NONBLOCK);cout << " set " << fd << " nonblock done " << endl;}int main(){char buffer[1024];// 设置标准输入为非阻塞IOSetNonBlock(0);while(true){// cout << "Please Enter# ";ssize_t n = read(0, buffer, sizeof(buffer) - 1);if(n > 0){buffer[n - 1] = 0;cout << "echo: " << buffer << endl;}else if(n == 0){cout << "read done" << endl;break;}else{if(errno == EWOULDBLOCK){// do other thing...}else{cerr << "read error" << endl;break;}//cerr << "read error, n = " << n << ", errno code: " << errno << ", errstr: " << strerror(errno) << endl;sleep(1);}}return 0;}
相关文章:

【计算机网络】高级IO模型
高级IO模型 一、 理解 IO二、认识五种高级 IO 模型1. 阻塞 IO2. 非阻塞IO3. 信号驱动 IO4. IO 多路转接5. 异步 IO 三、高级 IO 重要概念1. 阻塞和非阻塞2. 同步通信和异步通信 四、非阻塞 IOfcntl 一、 理解 IO 当我们调用系统接口 write、read 的时候,本质是把数…...

LabVIEW电动汽车直流充电桩监控系统
LabVIEW电动汽车直流充电桩监控系统 随着电动汽车的普及,充电桩的安全运行成为重要议题。通过集成传感器监测、单片机技术与LabVIEW开发平台,设计了一套电动汽车直流充电桩监控系统,能实时监测充电桩的温度、电压和电流,并进行数…...

前端学习<二>CSS基础——08-CSS属性:定位属性
CSS的定位属性有三种,分别是绝对定位、相对定位、固定定位。 position: absolute; <!-- 绝对定位 -->position: relative; <!-- 相对定位 -->position: fixed; <!-- 固定定位 --> 下面逐一介绍。 相对定位 相对定位:让…...
88. 合并两个有序数组(javascript)
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。 注意:最终,合并后数组…...
机器学习_集成学习_梯度提升_回归_决策树_XGBoost相关概念
目录 1. 机器学习 使用监督吗?什么又是监督学习? 2. 与XGBoost 类似的机器学习方法有哪些? 3. 随机森林方法 和 梯度提升方法 有什么区别? 分别应用于什么场景? 4. 决策树回归方法 和 Gradient Boosting类回归方法…...

ABAP 字段类型不一样导致相加之后金额错误
文章目录 ABAP 字段类型不一样导致相加之后金额错误写在前面的总结示例程序1汇总MSEG表和MLDOC表 ABAP 字段类型不一样导致相加之后金额错误 写在前面的总结 如果需要不同底表的字段相加的值,那么最好是根据条件去分别算出那些值放在临时内表里面,再去…...

【L1距离和L2距离】Manhattan Distance Euclidean Distance 解释和计算公式
距离度量 特征空间中两个实例点的距离可以反映出两个实力点之间的相似性程度,使用的距离可以是欧式距离,也可以是其他距离。 欧氏距离(L2距离):最常见的两点之间或多点之间的距离表示法,又称之为欧几里得度量,它定义于…...

自动发卡平台源码优化版,支持个人免签支付
源码下载地址:自动发卡平台源码优化版.zip 环境要求: php 8.0 v1.2.6◂ 1.修复店铺共享连接时异常问题 2024-03-13 23:54:20 v1.2.5 1.[新增]用户界面硬币增款扣款操作 2.[新增]前台对接库存信息显示 3.[新增]文件缓存工具类[FileCache] 4.[新增]库存同…...

如何使用固定公网地址远程连接Python编译器并将运行结果返回到Pycharm
文章目录 一、前期准备1. 检查IDE版本是否支持2. 服务器需要开通SSH服务 二、Pycharm本地链接服务器测试1. 配置服务器python解释器 三、使用内网穿透实现异地链接服务器开发1. 服务器安装Cpolar2. 创建远程连接公网地址 四、使用固定TCP地址远程开发 本文主要介绍如何使用Pych…...

Java设计模式—备忘录模式(快照模式)
定义 备忘录模式提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原,很多软件都提供了撤销(Undo)操作&#…...

没学数模电可以玩单片机吗?
我们首先来看一下数电模电在单片机中的应用。数电知识在单片机中主要解决各种数字信号的处理、运算,如数制转换、数据运算等。模电知识在单片机中主要解决各种模拟信号的处理问题,如采集光照强度、声音的分贝、温度等模拟信号。而数电、模电的相互转换就…...
FlinkSQL之Flink SQL Join二三事
Flink SQL支持对动态表进行复杂而灵活的连接操作。 为了处理不同的场景,需要多种查询语义,因此有几种不同类型的 Join。默认情况下,joins 的顺序是没有优化的。表的 join 顺序是在 FROM 从句指定的。可以通过把更新频率最低的表放在第一个…...

某某消消乐增加步数漏洞分析
一、漏洞简介 1) 漏洞所属游戏名及基本介绍:某某消消乐,三消游戏,类似爱消除。 2) 漏洞对应游戏版本及平台:某某消消乐Android 1.22.22。 3) 漏洞功能:增加游戏步数。 4…...

SpringBoot动态数据源实现
一、背景 一个应用难免需要连接多个数据库,像我们系统起码连接了5个以上数据库,AWS RDS主库,ECS自搭MySQL从库,工厂系统三个SQLServer数据库,在线网站MySQL数据库,记得很早以前是用SessionFactory配置&…...

计算机网络常见题(持续更新中~)
1 描述一下HTTP和HTTPS的区别 2 Cookie和Session有什么区别 3 如果没有Cookie,Session还能进行身份验证吗? 4 BOI,NIO,AIO分别是什么 5 Netty的线程模型是怎么样的 6 Netty是什么?和Tomcat有什么区别,特点是什么? 7 TCP的三次…...
富格林:可信招数揭发防备暗箱陷阱
富格林悉知,在风云变幻的金融市场中,炒贵金属是一项具有高收益潜力的投资方式。但投资是风险与收益共存的,因此我们在做单投资过程中需总结可信招数揭发暗箱陷阱,防备受害亏损。以下总结几点可信的投资技巧,希望能够帮…...

获取高德安全码SHA1
高德开发者平台上给的三种方法 获取安全码SHA1,这里我自己使用的是第三种方法。 1、通过Eclipse编译器获取SHA1 使用 adt 22 以上版本,可以在 eclipse 中直接查看。 Windows:依次在 eclipse 中打开 Window -> Preferances -> Androi…...

关于RPC
初识RPC RPC VS REST HTTP Dubbo Dubbo 特性: 基于接口动态代理的远程方法调用 Dubbo对开发者屏蔽了底层的调用细节,在实际代码中调用远程服务就像调用一个本地接口类一样方便。这个功能和Fegin很类似,但是Dubbo用起来比Fegin还要简单很多&a…...

pulsar: kafka on pulsar之把pulsar当kafka用
一、下载协议包(要和pulsar版本比较一致) https://github.com/streamnative/kop/releases?q2.8.0&expandedtrue二、在pulsar的根目录创建一个protocols目录,将上述包放到这个目录里 三、编辑broker.conf(如果是集群)或者standalone.con…...
七月论文审稿GPT第4版:通过paper-review数据集微调Mixtral-8x7b
模型训练 Mixtral-8x7b地址:魔搭社区 GitHub: hiyouga/LLaMA-Factory: Unify Efficient Fine-tuning of 100 LLMs (github.com) 环境配置 git clone https://github.com/hiyouga/LLaMA-Factory.git conda create -n llama_factory python3.10 conda activate lla…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...

2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...