Linux 文件描述符

文件描述符简述

  一个Linux进程启动后,会在内核空间创建一个PCB控制块,PCB内部有一个文件描述符表,记录着当前进程所有可用的文件描述符,即当前进程所有打开的文件。除了文件描述符表,系统还需要维护另外两张表:①、打开文件表 ②、i-node表

文件描述符表每个进程都有一个,打开文件表和i-node表整个系统只有一个,它们三者的关系如图:

其中文件描述符标志(close-on-exec),如果某个文件符设置了该标志,fcntl(fd, F_SETFD, 1), 则在该进程调用exec函数之前为exec族函数关闭对应的文件描述符。

  • 在进程 A 中,文件描述符 1 和 20 都指向了同一个打开文件表项,标号为 23,这可能是通过调用 dup()、dup2()、fcntl() 或者对同一个文件多次调用了 open() 函数形成的。
  • 进程 A 的文件描述符 2 和进程 B 的文件描述符 2 都指向了同一个文件,这可能是在调用 fork() 后出现的(即进程 A、B 是父子进程关系),或者是不同的进程独自去调用 open() 函数打开了同一个文件,此时进程内部的描述符正好分配到与其他进程打开该文件的描述符一样。
  • 进程 A 的描述符 0 和进程 B 的描述符 3 分别指向不同的打开文件表项,但这些表项均指向 i-node 表的同一个条目(标号为 1976);换言之,它们指向了同一个文件。发生这种情况是因为每个进程各自对同一个文件发起了 open() 调用。同一个进程两次打开同一个文件,也会发生类似情况。

结合Linux源码的分析

对于操作系统,进程就是一个数据结构,Linux源码(常见部分)如下:

struct task_struct {
    // 进程状态
    long              state;
    // 虚拟内存结构体
    struct mm_struct  *mm;
    // 进程号
    pid_t             pid;
    // 指向父进程的指针
    struct task_struct __rcu  *parent;
    // 子进程列表
    struct list_head        children;
    // 存放文件系统信息的指针
    struct fs_struct        *fs;
    // 一个数组,包含该进程打开的文件指针
    struct files_struct     *files;
};

 task_struct就是 Linux 内核对于一个进程的描述,也可以称为「进程描述符」。mm指向的是进程的虚拟内存,也就是载入资源和可执行文件的地方;files指针指向一个数组,这个数组里装着所有该进程打开的文件的指针。

  每个进程被创建时,files的前三位被填入默认值,分别指向标准输入流、标准输出流、标准错误流。我们常说的[文件描述符]就是指这个文件指针数组的索引。如果此时去打开一个新的文件,它的文件描述符会是3。POSIX标准要求每次打开文件时(含socket)必须使用当前进程中最小可用的文件描述符号码。

输入重定向:程序想读取数据的时候就会去files[0]读取,所以我们只要把files[0]指向一个文件,那么程序就会从这个文件种读取数据:$ command < file.txt

输出重定向:把files[1]指向一个文件,那么程序的输出就不会写入到显示器,而是写入到这个文件中:$ command > file.txt

管道符:把一个进程的输出流另一个进程的输入流接起一条「管道」,数据就在其中传递:$ cmd1 | cmd2 | cmd3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值