Liunx:文件fd、重定向、管道

文件fd: 

        操作系统运行中一定存在着许多被打开的文件,这些文件需要被管理。一个进程会打开若干个文件。一个文件如果在操作系统中被打开,那么必须给该文件创建一个文件对象,包含被打开文件的各种属性。那么进程与文件的关系就变成了PCB和该文件对象的关系。

        未打开的文件被保存在磁盘中,所以fopen注定是一个要访问磁盘的过程,也就是访问IO的过程。

        fopen需要的参数 ,当前路径:指的是进程当前所在的路径。fopen一定是被某个进程所调用的,这个当前路径指的就是该进程的当前路径。进程的属性中是包含了该进程所在的路径的。

fe478a791c4a41399bde212f71a366be.png

        所以调用fopen时,系统会把 进程的当前路径带上,cwd--current work direction。

        如果修改进程的cwd,那么fopen就会把文件默认新建在这个修改后的目录上。chdir该系统调用可以为进程改变当前路径:

dcc64e3115c947c6855165165a790c17.png

        fwrite()在写入之前都会将文件进行清空。cat log > txt .重定向到一个文件每次都是清空的写。效果相当于这里的fwrite()一w的属性打卡文件。

        \0终止符是c的规定,而不是文件的规定。

        C/c++都会默认打开三个输入输出流:

2c68ed7a27974af480e7b38bbd8850a0.png

文件操作系统调用:

        访问文件本质是访问硬件,所有访问硬件的库函数一定要封装系统调用接口。

        2 号man手册。open();

588ae517e3db4c799a72b917c2a5e18b.png

        比特级别的标志位:

5464d61672d9455690594371dc6a456c.png

         open系统调用返回的整形是文件描述符,分配规则是从0下标开始没有被使用的位置。

        0是stdin ,1是stdout,2是stderr。关掉其中之一的输入输出流,然后在使用open打开一个文件,该文件描述符被分配为那个被关掉的io流的描述符,那么从现象上看,close(1),之后再打开文件,之后的cout,printf依旧会向描述符为1的文件中输出,就像是输出被重新定向。所以输出重定向说的就是将进程默认打开的输入输出修改为自己指定的文件。

752f7f6dcd67426ca05a5e895a7836b1.png

 重定向:

        当close关闭某个默认流以后,使用C库函数中的文件操作会出现与open同样的效果。

        即可在用户层或者操作系统层修改文件描述符表,但是用户级别的进程依旧向规定的输出写入。

        修改文件描述符表的系统接口:dup2()

381d76063d1f4471b267ff904262633a.png

        oldfd覆盖newfd

        open系统调用返回的int整形是一个表的下标,而其内容是一个指向文件结构体的指针,将相应文件描述符,即表中相应下标位置的指针修改,就能完成一次重定向,即不再需要手动close()再重新打开;

        这里dup接收的两个整形,注意c的文件接口是一个指针类型的,用c接口打开文件是不知道文件fd,所以dup2 ()通常与open()系统调用配合使用。open()返回的直接是新打开文件的文件描述符。

        当把open()的打开方式的参数设置为追加写时,输出重定向>的效果变成了追加重定向>>。

        read()系统调用的返回值返回一个整形,即读到了多少个字节。read()的参数中有一个指定读多少个字节参数。有时实际读到的大小不一定是期望的大小。这就是这个返回值的含义。

        若将标准输入修改成一个文件,即本来从键盘读,变成从一个文件中读,这就是cat指令的原理。输入重定向。

1f720edfa8e84042bc424847c0ba96c1.png

 进程的替换,包括数据和执行代码的替换与打开的文件之间存在这隔离,进程的替换不会影响当前进程的所打开的关联文件。相应的文件描述符指向哪些文件,进程替换后依旧指向原来的文件。

 为什么要有两个文件描述符指向标准输出

       c0d3ad120d0d48abb5b5e425d6089408.png

        现象是被重定向的只是stdout,保证程序在需要重定向后,依旧可以向显示屏打印错误。

        重定向指令的全写:文件名后加文件描述符

8f6c8fc1d3034d14bb6cbe903f1af757.png

进程间通信 :    

        vscode链接在进程间通信上一节。

        进程间通信:什么是通信,为什么通信,怎么通信?

        通信就是一个进程想把数据给另一个进程,但是因为进程之间具有独立性,所以直接给是不行的,所以必须有通信的方案。

        通信传递数据指令或者进行多进程之间的协同,或者一个进程想通知另一个进程某些事情发生了

        怎么通信?

        首先要让通信的双方看到同一份公共资源,这个资源不能属于通信的任何一方,一般而言,这个资源由操作系统提供,但是操作系统一般不会让进程访问自己的资源,所以要实现进程访问该资源,就要提供一系列的系统调用接口。所以在底层,由操作系统提供通信的方案和一系列接口。一系列的标准被定义。

3af61b6e75d04138b7428e184e5c3dc2.png

e6bad8a04bb047c4937d607122c6fa96.png

        前者使用的最多的,后者需要了解。

        首先,在没有这个标准时,进程间通信可以基于文件的方式进行通信,即管道。

        管道是unix最古老的的通信方式,把从一个进程连接到另一个进程的数据流叫做管道。

        首先一个文件如果可以被多个进程打开并访问,那么该文件不就直接作为公共资源了吗?一个进程写,一个进程读。思想是对的,但是基于文件级的通信,意味着要访问外设,那么随之而来的就是效率问题。

        管道基于上述思想,但是不真正的向磁盘做刷新,可以向内存刷新 。

5c80a41c235e4dc4aa393dadb2c8b9f9.png

        原理、接口与编程:

        a5bce62a87cc4556ac51ef0815ed894d.png        

         操作系统可以为进程打开一种内存级文件,这种文件不真正的在磁盘上有相应的存储,而只是在内存中,并向其他的普通文件一样,有着文件inode,以及一系列方法。

        我们创建一个进程,该进程fork出一个子进程,该子进程复制了父进程的task_struct,包括file_struct,这个file_struct保存着该进程可以访问的文件的详细信息。这张表是被复制的,子进程父进程各有一分,但是该表指向的资源确实同一份:

f0a131b0a6e044fcbff6a5d5bfd78838.png

         这就意味着父子进程可以看到同一份内存级文件。管道就是文件。

        一个问题在于,父进程若是以只读的方式打开文件,那么子进程也只有只读的权限,故两进程都是只读,如何通信??
 

9d940a515ae44957bb6712bfa1744518.png

        解决办法是,父进程以读写的方式打开文件,子进程又具有读写权限,再根据具体场景的需求,父子进程选择性的关闭读写端 。

        一个进程对打开一个文件两次,一次以只读打开,一次以写方式打开。用这种方式是因为,如果对一个文件以读写的方式打开,该进程仅创建一个file结构体,fork()出子进程,相应的复制该结构体,该结构体中仅包含一个文件的偏移量,当你写入以后,偏移量指向文件末尾,那么如何读??子进程每次都要调整文件偏移量再读吗?

        所以我们将一个文件打开两次,OS为该进程创建了两个file结构体,然后父子进程选择性的关闭读写端,那么文件的读写偏移量就互不影响。

        另一个问题是,父子进程各自关闭一个读端一个写端,意味着两个进程之间只能选择单向通信,为什么不将各自进程的读写端都保留,实现双向通信呢??原因在于,虽然文件打开了两次,并且有两个file结构体,但是两个结构体指向的同一个文件缓冲区,当父进程写入,他接下来要进行读,如何判断这次读取的缓冲区的内容是我上次写入的还是子进程写入的??

        如果硬要以这种文件级的形式实现双向通信,当然可以单独的设计出一套数据结构来实现,但是我们直接使用文件这一套现有的结构,目的就是为了简便,所以这里只实现了单向通信。

        所以这也是为什么这种通信方式叫做管道的原因,像生活中的自来水管道等等此类,都是一端入,一端出。

54684b806adf468db9ae567e7086c50f.png

         这种方式的的通信,只要需要通信的进程双方,有一方是直接或者间接被fork()出的,也就是二者之间存在着父子,兄弟或者祖孙关系,就可以实现通信。

        同时这种通信方式,我们不需要内存级文件的名称或者inode,所以叫做再加个定语叫匿名管道。

接口与编程:

        到此为止,上述一直在阐述原理,还没有实现一个真正的通信。下面介绍OS为我们封装的接口。

        man 2 pipe:

        

f3584eb69b6649aab62d474c89435caa.png

        他的作用就是为我们以读写的方式打开一个内存级文件,传入一个输出型参数,将它为我们分别以读和写方式创建的文件描述符返回。0下标为读端,1下标位置为写端。

        

#include<iostream>
#include<unistd.h>
#include<string.h>
#include <sys/types.h>#include <sys/wait.h>using namespace std;//pipe
//
int main()
{pid_t pid_1 =getpid();cout<<"main::pid::"<<pid_1<<endl;int pipefd[2]={0};int n=pipe(pipefd);if(n<0){cout<<"pipe2() error::"<<endl;}else{cout<<"create sucessfully pipe... "<<endl;}cout<<"fork...."<<endl;pid_t ch_pid=fork(); //创建子进程if(ch_pid<0){cout<<" fork sucessfully ...."<<endl<<endl;//sleep(1);}if(ch_pid==0){char buffer[1024]="0"; //子进程缓冲区//children//wirtecout<<"child::close side of read..."<<endl;sleep(1);close(pipefd[0]); //关闭读端cout<<"child ::input buffer..."<<endl;snprintf(buffer,sizeof(buffer)-1," I am child : pid::%d",getpid());//cout<<"child::buffer::content::"<<buffer<<endl;sleep(1);cout<<"child::write....."<<endl;n =write(pipefd[1],buffer,strlen(buffer));sleep(1);if(n>0){cout<<"child::write sucessfull ..."<<endl;}else {cout<<"child::wrte::error..."<<endl;}//sleep(5);}//fatherclose(pipefd[1]);//关闭写端sleep(5); //等待子进程写char buffer[1024]="0";cout<<"father::read...."<<endl;n =read(pipefd[0],buffer,sizeof(buffer));if(n>0){buffer[n]=0;cout<<"father::read sucessfully.... "<<endl;;}cout<<"father::content:"<<buffer<<endl;n= waitpid(ch_pid,0,0);if(n>0){cout<<"wait sucessful ..."<<endl;}return 0;
}

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

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

相关文章

如何产看SQL 查询的执行时间

要查看 SQL 查询的执行时间&#xff0c;尤其是毫秒级别&#xff0c;可以使用以下几种方法&#xff1a; 方法 1&#xff1a;使用 SET STATISTICS TIME 查看执行时间 SET STATISTICS TIME 会显示执行时间的详细信息&#xff0c;包括 CPU 时间和总耗时。启用后&#xff0c;SQL S…

linux笔记(DNS)

一、概念 DNS&#xff08;Domain Name System&#xff09;DNS 是一种分布式网络目录服务&#xff0c;主要用于将人类易于记忆的域名&#xff08;如 www.example.com&#xff09;转换为计算机可识别的 IP 地址&#xff08;如 192.168.1.1&#xff09;。它就像是互联网的电话簿&a…

Power Pivot、Power BI 和 SQL Server Analysis Services 的公式语言:DAX(数据分析表达式)

DAX&#xff08;Data Analysis Expressions&#xff09;是一种用于 Power Pivot、Power BI 和 SQL Server Analysis Services 的公式语言&#xff0c;旨在帮助用户进行数据建模和复杂计算。DAX 的设计初衷是使数据分析变得简单而高效&#xff0c;特别是在处理数据模型中的表关系…

优衣库在淘宝平台的全方位竞品分析与店铺表现研究:市场定位与竞争策略透视

优衣库品牌在淘宝平台的全方位竞品与店铺表现分析 一、品牌商品分析 1.商品列表与分类分析&#xff08;数据来源&#xff1a;关键词商品搜索接口&#xff1b;获取时间&#xff1a;2024.08.30&#xff09; 商品类别分布柱状图&#xff1a; 根据关键词商品搜索接口获取到的优衣…

设计模式-七个基本原则之一-里氏替换原则

里氏替换原则&#xff08;LSP&#xff09;面向对象六个基本原则之一 子类与父类的替代性&#xff1a;子类应当能够替代父类出现的任何地方&#xff0c;且表现出相同的行为。行为的一致性&#xff1a;子类的行为必须与父类保持一致&#xff0c;包括输入和输出、异常处理等。接口…

开源数据库 - mysql - innodb源码阅读 - master线程(一)

master struct /** The master thread controlling the server. */void srv_master_thread() {DBUG_TRACE;srv_slot_t *slot; // 槽位THD *thd create_internal_thd(); // 创建内部线程ut_ad(!srv_read_only_mode); //断言 srv_read_only_mode 为 falsesrv_main_thread_proce…

RocketMQ 自动注入消费者

目录 前言一、情景介绍二、问题分析三、代码实现 前言 之前接到一个需求&#xff0c;我们项目的技术负责人希望通过配置的形式&#xff0c;在项目启动的时候自动根据配置生成对应的消费者 觉得还有点意思&#xff0c;随即记录一下~ 一、情景介绍 比如我这里有一个消费者 Mes…

数据结构(C语言版)(第2版) 课后习题答案 李冬梅

数据结构(C语言版)(第2版) 第1章 绪论 1.简述下列概念:数据、数据元素、数据项、数据对象、数据结构、逻辑结构、存储结构、抽象数据类型。 答案: 数据:是客观事物的符号表示,指所有能输入到计算机中并被计算机程序处理的符号的总称。如数学计算中用到的整数和实数…

Vue 自定义icon组件封装SVG图标

通过自定义子组件CustomIcon.vue使用SVG图标&#xff0c;相比iconfont下载文件、重新替换更节省时间。 子组件包括&#xff1a; 1. Icons.vue 存放所有SVG图标的path 2. CustomIcon.vue 通过icon的id索引对应的图标 使用的时候需要将 <Icons></Icons> 引到使用的…

吴恩达深度学习笔记:卷积神经网络(Foundations of Convolutional Neural Networks)4.9-4.10

目录 第四门课 卷积神经网络&#xff08;Convolutional Neural Networks&#xff09;第四周 特殊应用&#xff1a;人脸识别和神经风格转换&#xff08;Special applications: Face recognition &Neural style transfer&#xff09;4.9 内容代价函数&#xff08;Content cos…

LeetCode46. 全排列(2024秋季每日一题 57)

给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 示例 2&#xff1a; 输入&#xff1a;nums …

界面控件DevExpress WPF中文教程:Data Grid——卡片视图设置

DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序&#xff0c;这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 无论是Office办公软件…

MySQL 数据表常用编码类型解析

文章目录 MySQL 数据表常用编码类型解析一、字符集与编码简介二、MySQL 中的常用编码类型1. ASCII 编码2. Latin1 编码3. UTF-8 编码4. UTF-8mb4 编码5. UTF-16 编码 三、如何选择合适的编码类型四、编码转换和兼容性问题五、总结 MySQL 数据表常用编码类型解析 在 MySQL 数据库…

LLM训练”中的“分布式训练并行技术;分布式训练并行技术

目录 “LLM训练”中的“分布式训练并行技术” 分布式训练并行技术 数据并行 流水线并行:按阶段(stage)进行切分 张量并行 序列并行 多维混合并行 自动并行 MOE并行 重要的分布式AI框架 “LLM训练”中的“分布式训练并行技术” 随着深度学习技术的不断发展,特别是…

Ubuntu开启FTP与SSH服务

在配置开发环境时&#xff0c;这两个配置感觉是最有用的&#xff0c;开启FTP服务可以将远程linux上的文件映射到Windows上&#xff0c;不管是使用虚拟机还是嵌入式linux设备&#xff0c;特别在开发写代码的时候&#xff0c;映射到Windows上使用VS code打开编写比在linux上编写舒…

虚拟现实技术及其在教育领域的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 虚拟现实技术及其在教育领域的应用 虚拟现实技术及其在教育领域的应用 虚拟现实技术及其在教育领域的应用 引言 虚拟现实技术概述…

搜维尔科技:Varjo XR-4在教育科研领域应用

医学教育与培训&#xff1a; • 解剖学教学&#xff1a;传统的解剖学教学依赖于教科书、图片或实体标本&#xff0c;学生对于人体结构的空间关系理解存在一定难度。而使用Varjo头显&#xff0c;学生可以沉浸在虚拟的人体解剖环境中&#xff0c;全方位、多角度地观察人体的各个…

Java 源码中的 Unicode 逃逸问题,别被注释给骗了

背景 看了一段项目源码&#xff0c;定义了一个 List 对象&#xff0c;往该列表对象 add 的代码前面有注释符号&#xff0c;但是程序运行时列表中却存在对象&#xff0c;为什么呢&#xff1f;仔细看了一下&#xff0c;注释符号和 add 代码之间有一个特殊符号 \u000d&#xff0c…

基于python的机器学习(一)—— 基础知识(Scikit-learn安装)

目录 一、机器学习基础 1.1 机器学习概述 1.2 监督学习、无监督学习和强化学习 1.3 聚类、分类、回归、标注 1.3.1 聚类 1.3.2 分类 1.3.3 回归 1.3.4 标注 1.4 机器学习、人工智能和数据挖掘 1.5 机器学习的三个要素 二、Scikit-learn 机器学习库 2.1 Scikit-lea…

React 入门课程 - 使用CDN编程React

1. 第一个React 注意&#xff1a;在vscode里&#xff0c;使用Live Server来运行html文件。 index.html <html><head><link rel"stylesheet" href"index.css"><script crossorigin src"https://unpkg.com/react17/umd/react.de…