【Linux】fd_重定向本质

hello~ 很高兴见到大家! 这次带来的是Linux系统中关于基础 IO这部分的一些知识点,如果对你有所帮助的话,可否留下你宝贵的三连呢?
个 人 主 页 : 默|笙


文章目录

  • 一、理解重定向本质
      • [1.1 linux分配文件描述符遵循最小可用原则- - -分配规则](#1.1 linux分配文件描述符遵循最小可用原则- - -分配规则)
      • [1.2 IO函数只认文件描述符,不认特定的文件](#1.2 IO函数只认文件描述符,不认特定的文件)
      • [1.3 dup2系统调用](#1.3 dup2系统调用)
  • 二、初步认识一切皆文件

一、理解重定向本质

1.1 linux分配文件描述符遵循最小可用原则- - -分配规则

  1. 在之前的学习中,我们知道每一个进程运行之后,都会默认打开三个文件,分别是标准输入流,标准输出流和标准错误流,它们分别对应文件描述符0、1、2。而进程新打开的文件则会分配从3开始依次往后的文件描述符。
cpp 复制代码
 10   int fda = open("log.txt1", O_WRONLY | O_CREAT | O_TRUNC, 0666);
 11   int fdb = open("log.txt2", O_WRONLY | O_CREAT | O_TRUNC, 0666);
 12   int fdc = open("log.txt3", O_WRONLY | O_CREAT | O_TRUNC, 0666);
 13   printf("fda: %d\n", fda);
 14   printf("fdb: %d\n", fdb);
 15   printf("fdc: %d\n", fdc); 
  1. 如果我们人为将这三个默认打开的文件关闭再打开一个新的文件log.txt会怎么样--->关闭标准输入流文件,那么文件描述符为0的位置就会空出来,这个时候3就不是最小且可以分配的文件描述符了,也就是说,log.txt的文件描述符会是0,而不是3。可以通过下面的代码进行验证:
cpp 复制代码
  9   close(0);                                                                                                                              
 10   int fp = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
 11   printf("fp: %d\n", fp);

1.2 IO函数只认文件描述符,不认特定的文件

  1. C语言里面stdin、stdout和stderr都是对文件描述符fd的抽象封装,这也就意味着这三个流它们是不认识这些文件描述符所对应的文件的。一般stdin对应键盘文件,stdout和stderr对应显示器文件。如果将这些fd对应的文件替换掉,是不是就能够实现从其他文件进行输入输出了呢?是的。我们可以用下面这段代码进行验证:
cpp 复制代码
 10   close(1);
 11   int fp = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC);
 12   printf("fp: %d\n", fp);        
  1. 这里可以看到,如果我们把标准输出流关闭之后,printf要打印的内容在test执行之后没有显示在显示器上,而是打印到了log.txt文件里面,这是因为printf这个io函数它只认文件描述符1,它会把内容打印到文件描述符1对应的文件里面。在把标准输入流关闭打开一个新文件log.txt之后,文件描述符1就归log.txt这个文件了,printf要打印的内容自然就会打印到文件log.txt里面,而非显示器文件了。这就是为什么我们执行test看不到打印的内容而查看log.txt文件能够看到打印内容的原因。
  1. 我们通过关闭原来的输入输出流然后打开新的文件来代替要进行IO操作的显示器,键盘文件来实现对不同的文件输入输出。不过,现在一般是先打开新文件,然后将这个新文件覆盖掉原来的输入输出流对应文件。替换原输入输出流(键盘 / 显示器)对应的文件描述符(0/1/2)来达到对其他文件的IO操作,这就是重定向的本质
  2. 这里替换标准输入流对应文件也是一样,它不会再从键盘读取数据而是从文件描述符0对应的文件里面读取数据。
cpp 复制代码
 10   close(0);
 11   int fp = open("log.txt", O_RDONLY);                                                                                                    
 12   printf("fp: %d\n", fp);
 13   char s[10];
 14   scanf("%s", s);
 15   printf("%s\n", s);
  1. 事先我往已经存在的文件 log.txt 输入了一串字符helloworld,然后将文件描述符0对应的文件改为log.txt,之后用scanf读取log.txt文件内容再打印到显示器上,如果我们不改变文件描述符0对应文件,那么它应该从键盘读取数据,改变之后自然就从log.txt文件里面读取数据了。

1.3 dup2系统调用

  1. dup2这个接口就是专门用来改变文件描述符的,它的原理是进行覆盖,即用oldfd对应的文件覆盖newfd原本的绑定关系。比如上面我们用 log.txt代替了文件描述符0/1对应的文件,那么log.txt对应的文件描述符就是oldfd,而文件描述符0/1就是newfd。
  2. 有了这个函数,就不用通过关闭再打开文件进行替换操作,而是直接进行覆盖。
    10.进行程序替换是不会影响到进程已经打开的文件的。

二、初步认识一切皆文件

  1. 我们知道Linux系统里面一切皆文件,那么硬件在Linux系统里面也会是一个文件。OS要对这些硬件文件进行管理,一定也是先描述再组织,也就是把硬件的属性等其他内容打包成一个结构体struct_file。
  2. 对每个硬件进行操作,其实无非两种,输入和输出操作即IO操作。但是每一个硬件设备它们的访问方式都各不相同,比如键盘是输入,它的输出操作没有意义,显示器则与之相反。每一个硬件设备都有自己的输入和输出操作(驱动方法),要让OS对这些硬件以及其他文件进行统一操作,就需要对struct_file进行改造,加入operations模块绑定对应专属的IO操作,这样就实现了对不同的硬件进行统一操作。它类似于c++里面的多态。

今天的分享就到此结束啦,如果对读者朋友们有所帮助的话,可否留下宝贵的三连呢~~
让我们共同努力, 一起走下去!

相关推荐
安科士andxe2 小时前
深入解析|安科士1.25G CWDM SFP光模块核心技术,破解中长距离传输痛点
服务器·网络·5g
小白同学_C5 小时前
Lab4-Lab: traps && MIT6.1810操作系统工程【持续更新】 _
linux·c/c++·操作系统os
今天只学一颗糖5 小时前
1、《深入理解计算机系统》--计算机系统介绍
linux·笔记·学习·系统架构
2601_949146535 小时前
Shell语音通知接口使用指南:运维自动化中的语音告警集成方案
运维·自动化
儒雅的晴天6 小时前
大模型幻觉问题
运维·服务器
Gofarlic_OMS7 小时前
科学计算领域MATLAB许可证管理工具对比推荐
运维·开发语言·算法·matlab·自动化
通信大师7 小时前
深度解析PCC策略计费控制:核心网产品与应用价值
运维·服务器·网络·5g
dixiuapp7 小时前
智能工单系统如何选,实现自动化与预测性维护
运维·自动化
不做无法实现的梦~7 小时前
ros2实现路径规划---nav2部分
linux·stm32·嵌入式硬件·机器人·自动驾驶
Elastic 中国社区官方博客7 小时前
如何防御你的 RAG 系统免受上下文投毒攻击
大数据·运维·人工智能·elasticsearch·搜索引擎·ai·全文检索