Linux系统下的文件描述符fd详解

本文探讨了Linux系统中的文件描述符(fd)概念,它是打开文件的唯一标识符。通过open函数获取fd,然后进行读写操作。文章还揭示了内核源码中与文件描述符相关的task_struct,files_struct,fdtable等结构,以及文件描述符表的层级结构,包括stdio的标准文件描述符和它们指向的structfile结构体。
摘要由CSDN通过智能技术生成

文章目录


本作者从代码及源码的角度来总结探究文件描述符fd
参考:韦东山Linux嵌入式视频

文件描述符

Linux系统下一切皆文件。文件描述符fd是操作系统中用来唯一标识一个已打开文件的整数。本质上来说就是索引,即根据索引值寻找到对应的文件,可对其进行相应的操作。
使用open函数打开文件返回后得到一个文件描述符,使用read和write函数通过文件描述符fd进行读写操作。所有执行I/O操作的系统调用都通过文件描述符来实现。

首先,创建一个test.c文件

vim test.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char **argv)
{
        if(argc != 2){
             printf("Usage:%s <file>\n",argv[0]);
             return -1;
        }

        int fd = open(argv[1], O_RDONLY);

        printf("fd = %d\n",fd);
        while(1){
                sleep(100);
        }
        return 0;
}

编译,且运行打开test.c文件,&:表示后台运行,产生一个进程17985,打印文件描述符fd=3。

gcc -o test test.c 
/test test.c &

在这里插入图片描述
ps查看后台进程资源运行情况
切换到proc虚拟文件系统查看进程信息,进入fd目录查看对应文件描述符fd=3指向的就是打开test.c
其中fd=0,1,2分别对应标准输入、标准输出、标准错误
在这里插入图片描述

内核源码
路径:include\linux\sched.h 重要结构体:struct task_struct

  • open函数的系统调用会进入内核调用内核函数,一个进程就会产生struct task_struct结构体。task_struct结构体用于管理进程,包含了一个进程所需的所有信息。这也是PCB(进程控制块)
  • task_struct结构体的成员变量含有struct files_struct结构体,files_struct结构体管理进程打开的所有文件的管理结构。
  • files_struct结构体的成员变量含有struct fdtable结构体,fdtable结构体管理进程的文件描述符表。
  • fdtable结构体的成员变量含有 struct file __rcu **fd结构体,file结构体表示一个打开的文件,并且包含了许多与文件操作相关的信息和属性。
1struct task_struct--->2struct files_struct *files--->3struct fdtable *fdt--->4struct file **fd

特别的,

 struct file __rcu **fd;      /* current fd array */

fd是一个二级指针,指向的类型是是struct file类型的指针,指向的地址存储的是strcut file*类型的元素,地址里的元素strcut file*指向的是struct file
fd指向一个数组,数组元素为指针,指针类型为srtuct file *。
文件描述符本质上是一个指向文件表项的索引或引用
0 :STDIN_FILENO 接收键盘的输入
1 :STDOUT_FILENO 向屏幕输出
2 :STDERR_FILENO 标准错误
3:上图打开的test.c文件
而这些又分别指向自己的struct file结构体,而这个结构体存放着该文件的一些重要信息
关系如下所示
请添加图片描述
在这里插入图片描述
读取read文件的过程,转载
请添加图片描述

  • 29
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ioctl()是Linux系统中的一个系统调用,用于向设备驱动程序发送控制命令。它可以完成一些特殊的、设备相关的操作,如打开、关闭、读写设备、设置设备属性等。 ioctl()的原型如下: ```c #include <sys/ioctl.h> int ioctl(int fd, unsigned long request, ...); ``` 其中,fd是设备文件描述符,request是一个控制命令,后面的可选参数是针对控制命令的参数。 ioctl()的控制命令是一个32位无符号整数,分为四个部分: 1. 控制命令的类型:是一个字母,用来标识该命令的类型,如 'S' 表示设置,'G' 表示获取等。 2. 控制命令的序号:是一个数字,用来标识该命令的具体操作,如设置设备属性、获取设备状态等。 3. 控制命令的参数类型:是一个字母,用来标识该命令的参数类型,如 'i' 表示整数,'p' 表示指针等。 4. 控制命令的参数数量:是一个数字,用来标识该命令的参数数量。 下面是一个使用ioctl()发送控制命令的例子: ```c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <errno.h> #include <sys/ioctl.h> #define DEVICE_FILE "/dev/mydevice" int main() { int fd; unsigned long cmd; int arg; fd = open(DEVICE_FILE, O_RDWR); if (fd < 0) { perror("open"); exit(EXIT_FAILURE); } cmd = MY_DEVICE_CMD; arg = 12345; if (ioctl(fd, cmd, arg) < 0) { perror("ioctl"); exit(EXIT_FAILURE); } close(fd); return 0; } ``` 在上面的例子中,我们打开了一个设备文件,并向该设备发送了一个控制命令。具体的操作由设备驱动程序来实现。 需要注意的是,ioctl()的使用是非常灵活的,因为控制命令的类型和参数类型都是自定义的。因此,ioctl()的使用需要根据具体的设备和驱动程序来进行学习和理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值