重定向-缓冲区

1.重定向
文件描述符对应的分配规则是什么?
尝试用这个代码 关闭0,1,2文件描述符,看看有什么现象?关闭哪个,你打开的文件fd应该就是哪个
重定向-缓冲区_第1张图片
结论:
从0下标开始,寻找最小的没有没使用的数组位置,它的下标就是新文件的文件描述符

如果先关闭1,再打开log.txt,那么根据文件描述符分配规则,新打开的文件被分配到了下标1
此时write不管就往1号下标里面写入,则此时现象就是本来应该向显示器文件写出,但现在是往文件log里面写
重定向-缓冲区_第2张图片
这就是重定向的原理,但是这样做太挫了
我们可以利用系统调用dup2来复制文件描述符表数组中下标对应的内容
重定向-缓冲区_第3张图片
dup2的接口形参设计的不好,和我们认为的新旧正好相反,但是有了这句 newfd be the copy of oldfd,new是old的拷贝,则得出最后只剩一个oldfd
按照重定向结果,最后一定只剩fd这个新打开的地址,则oldfd 传 fd , newfd 传 1,这样也完成了重定向 >。
代码:
重定向-缓冲区_第4张图片
追加重定向 >>
重定向-缓冲区_第5张图片
输入重定向:
系统调用read
重定向-缓冲区_第6张图片

重定向-缓冲区_第7张图片
本来read(0,…) 应该从键盘读入,现在从文件里面读入
重定向-缓冲区_第8张图片

重定向的本质:
对进程的指定文件描述符表进行内核级别的对文件描述符表中的地址进行拷贝的问题
这就叫输入输出重定向

在模拟实现shell时,我们可以实现一下 > >> < 这三个重定向,来看看是怎么做到的
重定向工作应该在子进程里面完成,因为如果在父进程部分重定向,会影响到父进程
现在的问题是:做了重定向的工作后进行程序替换,难道不影响吗?(替换后从0开始,那你这重定向工作还有效吗)
重定向-缓冲区_第9张图片
盘点一下学习进程周边相关的数据结构了
重定向-缓冲区_第10张图片

这张图左边称为内核数据结构,右边是内存管理
程序替换是把新的程序代码数据直接替换旧的代码和数据,他改的只是进程的部分,进程替换时不会创建新进程也不会对进程的数据结构做影响,未来该替换替换,该重定向重定向,这就完成了内存管理和文件操作之间的解耦

结论:进程历史打开的文件与进行的各种重定向关系都和未来进行程序替换无关!!
程序替换,并不影响文件访问!!

遗留问题:标准输出stdout 1 和标准错误 stderr 2,他们都是显示器文件,那么他们俩有什么区别?
代码
重定向-缓冲区_第11张图片
现象:为什么./test > normal.log ,只有normal mes写进去了,而erro mes正常打印?
重定向-缓冲区_第12张图片

因为重定向让1号内容指向文件normal.log,2号仍然指向显示器,所有2号还是往显示器打印
1和2 本质上没什么区别,只是分开各自独立
下面展示2个应用场景,
1、可以做到正常信息和错误信息分开打印
重定向-缓冲区_第13张图片

2、 打印到同一个文件中
命令行从左到右,1重定向到all.log ,然后把1里面的内容写到2里面,最终1和2都指向all.log
重定向-缓冲区_第14张图片

重定向-缓冲区_第15张图片

如何理解一切皆文件?

1、所有的操作计算机的动作都是以进程的形式进行操作的
所有访问文件的操作最终直接都是用进程的方式来访问文件的
计算机上进行的所有操作/任务 最终都会被系统解释成进程,所以进程是操作系统
帮用户完成任务的主要渠道

2、目前对文件的操作都依赖于进程操作,C/C++/你写的系统调用接口最终不都变成进程了吗,所以所有目前对文件的访问它都是以进程为载体去访问的

因为LInux下一切皆文件,操作系统看来这些外设和普通文件全都是普通文件,未来打开磁盘,显示器,键盘都是进程打开的,所以这些设备如果访问都可以以文件的方式被系统用open打开,因为一切皆文件,那么打开的文件都要在内核中创建数据结构 struct file
底层每个设备的读写方法都不一样,要对文件进行读写struct file如何和底层关联起来访问不同的设备呢?
所以linux又给我们提供了一个结构: 一张方法表的数据结构里面保存了函数指针,把外设的读写方法地址写入到这些函数指针中,完成关联。
上层不关心设备驱动层的方法具体如何实现,将来要读这个文件,调用函数指针指向的方法就可以了,至于函数指针指向显示器就显示器,键盘就键盘。
所以从VFS(虚拟文件系统)往上不用关心底层访问哪个外设了,上面就是用户了,用户看到的就是一切皆文件。
重定向-缓冲区_第16张图片

加了一层对应的软件层VFS就能屏蔽底层的差异
VFS层和设备驱动层不就是C++里面的多态吗?所以的struct file不就是传说中的基类吗?C中struct里只能写属性不能写方法,所以他用函数指针充当函数方法。
所有的这些struct device 不就是派生类吗?指针指向哪个对象的方法就访问哪个对象的方法这不就是多态吗?

你可能感兴趣的:(Linux,linux)