【lesson35】基础IO之fd周边问题

文章目录

  • 基础IO要讲的知识点介绍
  • fd周边问题

基础IO要讲的知识点介绍

1.复习一下C语言的接口
2.直接使用系统接口
3.分析系统接口的细节,引入fd(文件描述符)
4.fd的周边问题(fd的理解、fd和file的关系、fd分配规则、fd重定向…)

fd周边问题

我们前面学了fd,那么fd到底是什么?
进行访问文件必须先打开文件,那么一个进程可以打开多个文件吗?可以的!
一般而言进程 : 打开的文件 = 1 : n的关系
文件要被访问,前提是加载到内存中,才能被直接访问!

因为进程 : 打开的文件 = 1 : n的关系,那么如果多个进程都打开自己的文件呢?
系统中就会存在大量被打开的文件!
所以OS要不要把如此多的打开文件管理起来?要
如何管理?先描述,再组织!

在内核中如何看待打开的文件?
OS内部为了管理每一个被打开的文件,所以为每个打开的文件构建了struct file。
【lesson35】基础IO之fd周边问题_第1张图片
创建struct file的对象充当被打开的文件,如果有很多呢?
再用双链表组织起来

进程和文件的对应关系如下图:
【lesson35】基础IO之fd周边问题_第2张图片
再具体点
【lesson35】基础IO之fd周边问题_第3张图片

所以fd本质就是一个数组的下标的。

文件分两类:
1.被打开的文件(内存文件)
2.没有被打开的文件(磁盘文件)

而现在知道,文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。**每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!**所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件。
【lesson35】基础IO之fd周边问题_第4张图片
fopen和fwrite的底层调用逻辑
fopen->open->fd(用fd封装FILE文件)->FILE->*FILE**(返回给)->fopen

fwrite->FILE*->fd->write->write(fd,.....)->进程自己执行OS内部的write方法->能找到进程的task_struct->*files->file_struct->fd_array[fd]->struct_file->内存文件被找到->开始操作

理解了什么是fd接下来就要知道fd的分配规则到底是什么。
【lesson35】基础IO之fd周边问题_第5张图片
在这里插入图片描述
我们看到关闭0号文件,它占用的就是0号描述符。
所以fd的分配规则:最小的,没有被占用的文件描述符

输出重定向
【lesson35】基础IO之fd周边问题_第6张图片
运行结果
【lesson35】基础IO之fd周边问题_第7张图片
我们内容确实达到显示器上了,但是如果我们关闭1,显示器也就关闭了,这内容会打向哪里呢?
【lesson35】基础IO之fd周边问题_第8张图片
【lesson35】基础IO之fd周边问题_第9张图片
我们看到内容确实没打到显示器上。
那么打印到了哪里呢?
【lesson35】基础IO之fd周边问题_第10张图片
打印到了log.txt中,这就是输出重定向。
原理:
【lesson35】基础IO之fd周边问题_第11张图片

而接下来向1中写的内容不会写到stdout中只会写到log.txt中,这就是重定向的原理。
重定向本质:在OS内更改fd对应的内容指向!

输入重定向的演示:

 #include 
  2 #include <string.h>
  3 #include <unistd.h>
  4 #include <sys/types.h>
  5 #include <sys/stat.h>
  6 #include <fcntl.h>
  7 
  8 int main()
  9 {
 10   //默认打开0 1 2 关闭0号文件描述符
 11   close(0);
 12   int fd = open("log.txt",O_RDONLY,0666);
 13   if(fd < 0)
 14   {
 15     perror("open");
 16   }
 17   else
 18   {
 19     char buffer[64];
 20     while(fgets(buffer,sizeof(buffer),stdin) != NULL)
 21     {
 22 
 23       fprintf(stdout,buffer,NULL);                                                                                                                                  
 24     }
 		close(fd);
 39   }
 40   return 0;
 41 }

运行代码
【lesson35】基础IO之fd周边问题_第12张图片
我们看到本来应该从stdin读取的内容变成从log.txt里面读取。

追加重定向:
我们只要把输出重定向的O_TRUNC改成O_APPEND即可。
这里大家自己更加,我便不演示了。
【lesson35】基础IO之fd周边问题_第13张图片

我们之前都是自己手动关闭0,1的,这样太挫了,下面就有个函数帮助我们。
在这里插入图片描述
【lesson35】基础IO之fd周边问题_第14张图片
问题:
dup2拷贝是在拷贝什么?拷贝的是文件描述符数组里面的指针。
谁是谁的拷贝?
是把new拷给old?
还是把old拷给new?

看英文可知是把:oldfd拷贝给newfd。所以最后newfd里面的指针和oldfd一样
理解:

【lesson35】基础IO之fd周边问题_第15张图片
输出重定向更改
【lesson35】基础IO之fd周边问题_第16张图片
运行代码
【lesson35】基础IO之fd周边问题_第17张图片

追加重定向更改
【lesson35】基础IO之fd周边问题_第18张图片
运行代码
【lesson35】基础IO之fd周边问题_第19张图片
输入重定向这里就不更改了,逻辑一样大家自行更改即可。

如何理解一切皆文件呢?->Linux的设计哲学->体现在OS的软件设计层面!

LinuxC语言写的!如何用C语言实现面向对象,甚至是运行时多态呢?->struct类但是我们知道struct类是没有成员函数的那么如何实现呢?函数指针

【lesson35】基础IO之fd周边问题_第20张图片
底层不同的硬件,一定对应的是不同的操作方法!但是上面的设备都是外设,所以每一个设备都核心访问函数都可以是read,write的I/O操作。
所有设备都可以有自己的read和write,但是代码的实现一定是不一样的。
【lesson35】基础IO之fd周边问题_第21张图片

【lesson35】基础IO之fd周边问题_第22张图片
所以在struct file的这层往上就没有任何硬件的区别了
看待所有文件的方式,都统一成为了struct file->所以就有了Linux下一切皆文件的说法。

接下来就是缓冲区的理解
1.什么是缓冲区?就是一段内存空间
(这个空间谁提供?用户?语言?OS?)
2.为什么要有缓冲区?

故事
小明在云南大学想给远在北京邮电的小华送一些书过去。
送书有2种方法:
1.自己骑车送过去(写透模式(WT) 成本高,花时间多,慢)
2.快递发送点
【lesson35】基础IO之fd周边问题_第23张图片
这是写回模式(WB) 成本低,花时间少,快

那么顺丰是立马发送吗?
不是,是快递累积到一定数量后再发送

在这个故事里的顺丰就是典型的缓冲区的意义:目的是体改整机的效率

类比:
顺丰:缓冲区
小明:用户
小华:磁盘
书: 数据

缓冲区主要是为了提高用户的响应速度。

缓冲区刷新策略
顺丰发送策略对应缓冲区的刷新策略:
1.立即发送(立即刷新)
2.架子上的快递一行一行发送的行发送(行缓冲)
3.快递架子满了在发送(全缓冲)

特殊情况
1.用户强制刷新(fflush)
2.进程退出

缓冲策略 = 一般加特殊

那么缓冲区到底谁提供的?
C?OS?

写一段代码:
【lesson35】基础IO之fd周边问题_第24张图片
运行代码
【lesson35】基础IO之fd周边问题_第25张图片
我们发现把内容打印到stdout的内容重定向到log.txt中,log.txt中
C语言提供的接口打印了两次
OS提供的接口打印了一次
接来下我们把fork注释掉看一下,运行结果
【lesson35】基础IO之fd周边问题_第26张图片
【lesson35】基础IO之fd周边问题_第27张图片
这里说明一个问题,这个现象绝对个fork有关
那么为什么OS提供的接口打印一次,C提供的接口打印两次下次再说。

你可能感兴趣的:(linux,服务器,linux,网络)