[Linux]:高级IO

news2024/11/26 11:50:10

1. IO 理解

1.1 IO 的基本概念

I/O即输入/输出(input/output),是计算机系统中极为关键的操作环节。

在经典的冯诺依曼体系结构框架下,其核心在于数据的传输流向界定了输入与输出的概念。具体而言,当把数据从诸如键盘、鼠标等输入设备拷贝传输到计算机的内存当中,这一过程便被称作输入操作;而当数据从内存拷贝传输至像显示器、打印机这类输出设备时,就被定义为输出操作。

画板

从实际应用场景来看,对文件展开的读写操作实质上就是一种I/O体现。在这种情况下,与之对应的外部设备是磁盘,即读取磁盘上存储的文件内容至内存可视为输入操作,而将内存中的数据写入磁盘形成文件则属于输出操作。同样地,针对网络进行的读写操作同样归属于I/O范畴,这里与之对应的外设是网卡,例如从网络接收数据并存储到内存就是网络输入操作,将内存中的数据通过网卡发送到网络则是网络输出操作。

总的来说,I/O涵盖了计算机与外部设备之间数据交互的各类情形,是实现计算机系统与外界进行信息沟通、数据传递的重要途径,它使得计算机能够获取外部信息并将处理结果反馈出去,从而完成各种复杂的任务和功能实现。

1.2 OS 得知数据就像的方式

操作系统(OS)得知外设当中有数据可读取主要是通过中断机制来实现的。

首先,输入操作是指将数据从外设拷贝到内存的过程,但外设并非随时都有可供操作系统读取的数据。例如在网络访问场景中,用户发出请求报文后需等待从网卡读取服务器响应数据,而在此期间可能存在多种情况致使数据未就绪。

然后,操作系统不会主动频繁检测外设数据是否就绪,因为多数情况下外设无数据,主动检测效率低下。

实际情况是,当外设上有数据就绪时,该外设有权直接将控制信号以中断的形式发送给CPU中的中断控制器。中断控制器会依据中断信号的优先级顺序将其传送给CPU。

而在系统中存有中断向量表,它存储着中断信号与中断处理程序的映射关系。当CPU收到中断信号后,会自动暂停正在运行的程序,依据中断向量表找到并执行该中断信号对应的中断处理程序,待处理完毕后再返回原被暂停的程序继续运行,以此实现得知外设中有数据可读取并进行相应处理的流程。

理解上来说,这种基于中断的机制使得操作系统无需持续关注外设状态,避免了无效检测带来的资源浪费,同时又能及时响应外设的数据就绪情况,保证了数据读取的及时性和系统运行的高效性,是一种合理且高效的外设数据读取感知方式。

1.3 OS 处理网络数据

那么操作系统具体是如何处理网络数据的呢?当操作系统从网卡读取到数据包时,会创建 sk_buff 结构。它的 data 指针指向所读取的数据包。这些 sk_buff 结构以双链表形式组织,操作系统通过对双链表的操作来管理众多数据包。为保证高效的网络报文处理,sk_buff 结构本身需设计得高效。由于要被内核各协议共用,sk_buff 结构需兼容所有网络协议,这使其结构较为复杂。

为了方便理解,下面是一个简单的 sk_buff结构:

struct sk_buff {
    char* transport_header;
    char* network_header;
    char* mac_header;
    char* data;

    struct sk_buff* next;
    struct sk_buff* prev;
};

当操作系统从网卡读取一个数据包时,会依次将数据交给链路层、网络层、传输层、应用层进行解包和分用,最终将数据包中的数据交给了上层用户,而数据包解包与分用向上交付的过程,本质不过是 sk_buff中指针之间的交换。具体过程如下:

  1. 链路层处理:让 sk_buff 结构中的 mac_header 指针指向数据包,通过读取指针指向位置之后的数据获取链路层报头,剩余部分则是网络层要处理的有效载荷,完成链路层解包。
  2. 网络层处理:链路层将有效载荷“传递”给网络层,实际操作是让 sk_buff 结构中的 network_header 指针指向链路层报头之后的数据,然后读取网络层报头,完成网络层解包。
  3. 传输层处理:使 sk_buff 结构中的 transport_header 指针指向网络层报头之后的数据,再读取传输层报头,完成传输层解包。
  4. 数据交付给用户传输层解包后,依据所使用的传输层协议(如TCP或UDP),将剩余数据拷贝到相应的接收缓冲区,供用户读取。

发送数据时,依次在数据前拷贝对应的报头(链路层、网络层、传输层报头),最后根据协议将数据发送(UDP)或拷贝到发送缓冲区(TCP)。整个封装和解包过程中,数据的存储位置基本不变,主要是通过不同指针操作来实现处理。

2. 五种 IO 模型

五种 I/O 模型是在计算机网络编程等领域用于描述操作系统处理输入 / 输出(I/O)操作的不同方式,以下我将为你详细介绍:

2.1 阻塞 IO

阻塞IO(Blocking I/O)是一种在进行输入输出操作时,进程(或线程)会被阻塞的IO模型。

当进程发起一个IO操作时,阻塞 IO 的流程如下:

  • 如果所请求的数据尚未准备好(例如从网络读取数据时,数据还未到达网卡缓冲区;或者从文件读取数据时,文件内容还未加载到内存合适位置等情况),那么发起IO操作的进程就会进入阻塞状态。
  • 在阻塞状态下,进程会暂停执行后续代码,一直等待,直到所请求的IO操作完成,也就是数据准备好并且成功被读取到进程所指定的缓冲区(对于读取操作而言),或者数据成功从进程缓冲区发送出去(对于发送操作而言)。

例如,在一个简单的网络客户端程序中,如果使用阻塞IO从网络套接字读取服务器的响应数据,当客户端发出读取请求后,若服务器响应数据未到达,客户端程序就会阻塞在读取操作处,直到接收到完整数据才会继续执行后续流程。

2.2 非阻塞 IO

非阻塞IO(Non-Blocking I/O)是与阻塞IO相对的一种IO模型,在进行输入输出操作时,进程(或线程)不会因IO操作未完成而一直处于阻塞状态。

当进程发起一个IO操作时,非阻塞 IO 的流程如下:

  • 如果所请求的数据尚未准备好(比如从网络读取数据时,数据还未到达网卡缓冲区;或者从文件读取数据时,文件内容还未加载到内存合适位置等情况),发起IO操作的进程不会进入阻塞状态,而是会立即得到一个反馈结果,告知当前IO操作暂时无法完成,数据还未就绪。
  • 进程在得到数据未就绪的反馈后,可以继续执行后续的其他代码逻辑,而不是像阻塞IO那样一直等待。之后进程可以选择过一段时间再次发起相同的IO操作来检查数据是否已经准备好,直到成功完成IO操作(对于读取操作而言是将数据读取到进程所指定的缓冲区,对于发送操作而言是将数据从进程缓冲区发送出去)。

例如,在一个网络客户端程序中采用非阻塞IO从网络套接字读取服务器的响应数据,当客户端发出读取请求后,如果服务器响应数据未到达,客户端程序不会阻塞在读取操作处,而是可以继续去做诸如更新界面显示、处理其他用户输入等操作,并且会定期或根据一定策略再次发起读取请求来查看数据是否已经到达并可读取。

2.3 信号驱动 IO

信号驱动IO(Signal-Driven I/O)是另一种IO模型,与阻塞IO和非阻塞IO有所不同,它通过信号机制来处理输入输出操作。

当进程发起一个IO操作时:

  • 首先,进程会通过系统调用向内核注册一个信号处理函数,用于在IO操作完成时接收通知信号。这个注册过程告知内核当指定的IO操作就绪(比如数据准备好可读取,或者数据可从缓冲区成功发送出去等情况)时,要发送一个特定的信号给该进程。
  • 然后,进程可以继续执行后续的其他代码逻辑,而不会像阻塞IO那样因为等待IO操作完成而阻塞在此处。在注册完信号处理函数后,进程就去忙自己的其他事情了,不会不断地去轮询检查数据是否就绪,就如同非阻塞IO那样的操作在此模型下是不需要的。
  • 当所请求的IO操作最终完成时,内核会根据之前的注册,发送相应的信号给该进程。进程在接收到这个信号后,就知道对应的IO操作已经就绪了,于是会暂停当前正在执行的代码,转而执行之前注册好的信号处理函数来处理IO操作的后续事宜(比如将数据从内核缓冲区读取到进程指定的缓冲区,或者将进程缓冲区中的数据发送出去等)。

例如,在一个网络服务器程序中采用信号驱动IO来处理客户端的连接请求和数据传输。程序先向内核注册好针对连接请求和数据读取、发送等IO操作的信号处理函数。当有客户端发起连接请求或者有数据要传输时,内核会在相应操作完成后发送信号给服务器程序。服务器程序接收到信号后,就会执行对应的信号处理函数来处理这些IO相关的事宜,比如接受客户端连接、读取客户端发送的数据或者向客户端发送响应数据等,而在等待这些IO操作完成的过程中,服务器程序可以继续处理其他客户端的请求或者进行一些内部的数据维护等工作。

2.4 IO 多路转接

IO多路转接是一种高效的IO处理方式,与其他IO模型有所区别。

当进程使用IO多路转接时,流程如下:

  • 进程先通过系统调用(如 selectpollepoll)将多个IO事件对应的文件描述符交给内核进行监视。这些IO事件可以是多个套接字的读操作、写操作等。
  • 内核会同时监控这些文件描述符对应的IO事件。此时,进程不会因为等待某一个特定IO事件完成而被阻塞,它可以去执行其他的任务。
  • 当这些被监视的文件描述符中有一个或多个IO事件就绪(例如某个套接字有数据可读,或者可以写入数据),进程就可以会对就绪的IO事件进行处理,例如读取数据或者写入数据。

例如,在一个网络服务器程序中使用IO多路转接处理客户端请求。服务器将所有客户端连接对应的套接字文件描述符交给内核监视。当有新的客户端连接请求到来或者已有客户端发送数据时。服务器进程就可以根据具体情况,处理新连接或者读取/发送客户端数据,并且在等待数据就绪的过程中,服务器进程还可以处理其他事务,如记录日志、更新服务器状态等。

2.5 异步 IO

异步IO是一种高效的IO模型,与其他模型有明显差异。

当进程使用异步IO时,流程如下:

  • 进程发起一个IO操作后,不会等待这个IO操作完成,也不会等待数据是否就绪,而是可以直接继续执行后续的其他代码逻辑。
  • 当IO操作完成时(如数据已读取到指定位置或者数据已成功发送),系统会通过某种方式(比如回调函数、信号等)通知进程。进程收到通知后,再对已经完成的IO操作结果进行处理。

例如,在一个网络应用程序中采用异步IO来获取服务器的数据。当程序发起数据读取请求后,它会立刻去执行如检查更新、预加载其他资源等操作。一旦服务器的数据读取完成,系统会通过事先设定的回调函数通知程序,程序就可以对读取到的数据进行后续处理,如展示数据、分析数据等。

3. 同步通信与异步通信

3.1 同步通信

  • ****在同步通信的情境下,当发起一个调用操作时,调用者会一直处于等待状态,直至获取到该调用的最终结果才会继续后续的流程。也就是说,这个调用不会在未得到结果前就返回,只有当结果明确返回给调用者时,整个调用过程才算完成。

比如你在网上购买一件商品,点击“提交订单”按钮后(发起调用),页面会一直显示加载状态,直到系统处理完订单相关的所有流程,如库存检查、价格核算、支付确认等,并返回一个明确的提示,如“订单提交成功”或者告知你失败的原因(这就是得到返回值),你才能进行后续操作,比如继续浏览其他商品或者查看订单详情等。在这个过程中,你作为调用者(点击提交订单的操作主体)是主动在等待订单提交这个调用的结果。

3.2 异步通信

与同步通信截然不同,异步通信在调用发出之后,调用本身会立即返回,并不会马上给出结果。调用者在发出调用后可以继续去执行其他的任务或操作,而不需要一直等待结果。被调用者会在合适的时候,通过诸如更新状态让调用者可查看、发送通知消息或者执行回调函数等方式,来告知调用者关于该调用的最终结果。

还是以网上购物为例,当你点击“提交订单”按钮(发起调用)后,页面可能只是短暂显示一个提示,如“订单正在处理中”,然后你就可以继续浏览其他商品、查看购物车等其他操作了(因为调用已经返回,你可以继续做其他事)。之后,系统会通过发送短信通知你订单是否提交成功(这就是通过通知告知调用者结果),或者在订单页面更新订单状态供你查看(通过状态告知结果),又或者在后台执行一个回调函数来完成一些后续相关的处理(比如根据订单结果为你推荐相关商品等),而这些告知结果的操作都是在你已经继续进行其他活动之后发生的。

其中需要注意的是多进程/线程里的同步与互斥,和同步通信概念不同。进程/线程同步是保证数据安全下按序访问临界资源,避免饥饿。而同步IO则关乎进程/线程与操作系统关系,涉及是否主动参与IO过程。

4. 其他高级IO

非阻塞IO,记录锁,系统V流机制,I/O多路转接(也叫I/O多路复用),readv和writev函数以及存储映射IO(mmap),这些统称为高级IO。

5. fcntl 函数

我们在打开文件 open 时,默认为阻塞打开,但是用open函数携带O_NONBLOCKO_NDELAY选项就可以可用非阻塞的方式打开文件。

但是如果我们要将已打开文件或套接字设为非阻塞状态,需用用到fcntl函数,其用法如下:

  1. 函数原型:int fcntl(int fd, int cmd,… /* arg */);
  2. 参数说明:
  • fd:已打开的文件描述符。
  • cmd:要进行的操作,不同cmd取值对应不同功能,常见取值及功能如下:
    • F_DUPFD:复制一个现有的描述符。
    • F_GETFDF_SETFD:获得/设置文件描述符标记。
    • F_GETFLF_SETFL:获得/设置文件状态标记。
    • F_GETOWNF_SETOWN:获得/设置异步I/O所有权。
    • F_GETLKF_SETLKF_SETLKW:获得/设置记录锁。
  1. 返回值:函数调用成功,返回值取决于具体操作。函数调用失败,返回 -1,同时错误码会被设置。

然后通过以下代码可将指定文件描述符设为非阻塞状态:

bool SetNonBlock(int fd)
{
    int fl = fcntl(fd, F_GETFL);
    if (fl < 0){
        std::cerr << "fcntl error" << std::endl;
        return false;
    }
    fcntl(fd, F_SETFL, fl | O_NONBLOCK);
    return true;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2237564.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【GeoJSON在线编辑平台】(2)吸附+删除+挖孔+扩展

前言 在上一篇的基础上继续开发&#xff0c;补充上吸附功能、删除矢量、挖孔功能。 实现 1. 吸附 参考官方案例&#xff1a;Snap Interaction 2. 删除 通过 removeFeature 直接移除选中的要素。 3. 挖孔 首先是引入 Turf.js &#xff0c;然后通过 mask 方法来实现挖孔的…

【ReactPress】React + antd + NestJS + NextJS + MySQL 的简洁兼时尚的博客网站

ReactPress 是使用React开发的开源发布平台&#xff0c;用户可以在支持React和MySQL数据库的服务器上架设属于自己的博客、网站。也可以把 ReactPress 当作一个内容管理系统&#xff08;CMS&#xff09;来使用。 前言 此项目是用于构建博客网站的&#xff0c;包含前台展示、管理…

ZISUOJ 2024算法基础公选课练习一(1)

前言、 又是一年算法公选课&#xff0c;与去年不同的是今年学了一些纯C&#xff08;而不是带类的C&#xff09; 一、我的C模板 1.1 模板1 #include <bits/stdc.h> using i64 long long;int main() {std::cin.tie(nullptr)->sync_with_stdio(false);return 0; } 1…

【1】虚拟机安装

1.安装VMware WorkStation Pro VMware下载地址&#xff1a; 密钥&#xff1a;YF390-0HF8P-M81RQ-2DXQE-M2UT6 2.新建虚拟机 centos7下载地址&#xff1a;centos-7.9.2009-isos-x86_64安装包下载_开源镜像站-阿里云

【SpringBoot】SpringBoot自带的Jackson入门使用

导入依赖 springboot自带的&#xff0c;挨个点进去&#xff0c;就能找到 自定义对象转换器 import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModu…

软件工程概论项目(一),git环境的配置和平台代码的拉取

距离软工概论项目答辩还有五个周的时间&#xff0c;需要做一个项目&#xff0c;把心得体会都做一个记录。以便以后进行回顾和反思 这里写目录标题 一、环境的配置gitbash 一、环境的配置 gitbash 安装gitbash&#xff0c;简单说两句&#xff0c;git用于多人协作和代码托管&am…

分布式数据库中间件mycat

MyCat MyCat是一个开源的分布式数据库系统&#xff0c;它实现了MySQL协议&#xff0c;可以作为数据库代理使用。 MyCat(中间件)的核心功能是分库分表&#xff0c;即将一个大表水平分割为多个小表&#xff0c;存储在后端的MySQL服务器或其他数据库中。 它不仅支持MySQL&#xff…

万字长文解读深度学习——循环神经网络RNN、LSTM、GRU、Bi-RNN

&#x1f33a;历史文章列表&#x1f33a; 深度学习——优化算法、激活函数、归一化、正则化深度学习——权重初始化、评估指标、梯度消失和梯度爆炸深度学习——前向传播与反向传播、神经网络&#xff08;前馈神经网络与反馈神经网络&#xff09;、常见算法概要汇总万字长文解读…

一文了解什么是腾讯云开发

关于云开发的猜想 说到云开发&#xff0c;作为开发者的大家是否大概就有了想法。比如说过去的开发工作都是在自己本地电脑的开发工具&#xff0c;比如IDEA开发工具进行开发的&#xff0c;开发完成后再部署到服务器测试以及上线。那么腾讯云开发&#xff0c;是不是就是不用本地…

双指针算法的妙用:提高代码效率的秘密(2)

双指针算法的妙用&#xff1a;提高代码效率的秘密&#xff08;2&#xff09; 前言&#xff1a; 小编在前几日讲述了有关双指针算法两道题目的讲解&#xff0c;今天小编继续进行有关双指针算法习题的讲解&#xff0c;老规矩&#xff0c;今天还是两道题目的讲解&#xff0c;希望…

【Python】从入门开始抓取你想要的电影,一周可掌握基础,附完整源码

Python学习很简单&#xff0c;只是你走进了误区。 为什么你一定要先掌握枯燥的基础点后&#xff0c;再去做实际操作呢&#xff1f; 其实&#xff0c;你根本坚持不了那么长时间&#xff0c;但实际上你可以直接去做python项目。 不信&#xff1f;看看我做这个项目的思路&#x…

逐梦代码深林:Linux编译之舞,链接之诗——自举、动静态库的浪漫旅程

文章目录 问题引入&#xff0c;为什么要进行编译->汇编?一、详细解释编译器自举1. 从最初的二进制编程到汇编2. 第一代汇编编译器的诞生3. 编译器自举的出现&#xff1a;从汇编到更高级的编译器4. 自举的延续&#xff1a;从汇编到高级编程语言5. 为什么要进行编译器自举&am…

AI 写作(六):核心技术与多元应用(6/10)

一、AI 写作的核心技术概述 AI 写作在当今数字化时代正发挥着越来越重要的作用。它不仅极大地提高了写作效率&#xff0c;还为不同领域带来了创新的可能性。 AI 写作的核心技术主要包括基于模板的文本生成和基于深度学习的文本生成。基于模板的文本生成通常依赖预先设定的模板…

米家通过HomeAssistant控制笔记本电脑开关机

米家通过HomeAssistant控制笔记本电脑开关机 配置HomeAssistant配置EMQX mqtt自动化配置电脑关机实现电脑开机实现&#xff08;网络唤醒WOL包&#xff09; 环境准备&#xff1a; HomeAssistant&#xff1a;能配置接入米家的设备&#xff0c;我这里采用fnos安装MQTT服务器&…

QT信号和槽与自定义的信号和槽

QT信号和槽与自定义的信号和槽 1.概述 这篇文章介绍下QT信号和槽的入门知识&#xff0c;通过一个案例介绍如何创建信号和槽&#xff0c;并调用他们。 2.信号和槽使用 下面通过点击按钮关闭窗口的案例介绍如何使用信号和槽。 创建按钮 在widget.cpp文件中创建按钮代码如下 …

环境背景文本到语音转换

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;编程探索专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年11月9日23点20分 点击开启你的论文编程之旅https://www.aspiringcode.com/content?id100000000027&uida9ecaa6323844415b87…

MySQL初学之旅(1)配置与基础操作

目录 1.前言 2.正文 2.1数据库的发展历程 2.2数据库的基础操作 2.2.1启动服务 2.2.2创建与删除数据库 2.2.3数据类型 2.2.4创建表与删除表 2.3MySQL Workbench基础使用简介 3.小结 1.前言 哈喽大家好吖&#xff0c;今天博主正式开始为大家分享数据库的学习&#xff…

【环境搭建】使用Dockerfile构建容器搭建Kylin特定版本

Kylin的有些版本官方已经下架了&#xff0c;Docker Hub上也没镜像了&#xff0c;所以需要自己搭建以下&#xff0c;为了以后更方便快捷地使用&#xff0c;就编写了一个更轻量级的Dockerfile。 准备工作 本次搭建使用的源码包来自华为云镜像站&#xff0c;里面有Kylin各个版本…

【图】图学习

0 回顾数据结构逻辑 1 图的定义和基本术语 必须有顶点&#xff0c;可以没有边。 Cn2和2*Cn2&#xff08;数学上的&#xff0c;n个顶点取2个顶点&#xff09; 概念有些多。。。。。。 2 图的定义 3 图的存储结构 无向图的邻接矩阵 有向图的邻接矩阵 网&#xff08;有权图&#…

基于RMD算法模型的信号传输统计特性的matlab模拟仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于RMD算法模型的信号传输统计特性的matlab模拟仿真。参考的文献如下&#xff1a; 即通过RMD随机中点位置模型算法&#xff0c;实现上述文献的几个仿真图。 2.…