首先我们需要知道操作系统内维护了三个系统文件表:文件描述符表(file descriptor table),打开文件表(open file table),inode table。这三个表的结构见Table-1

我们知道在like-unix系统中所有的IO操作(包括socket等)都是基于文件描述符的。程序刚刚启动的时候已经默认帮我们分配了三个文件描述符,就是我们常用的0标准输入,1标准输出,2标准错误。如果此时进程再打开新的文件,它的文件描述符会加1也就是3。POSIX标准要求每次打开文件时(含socket)必须使用当前进程中最小可用的文件描述符号。

Table-1

文件描述符表(file descriptor table)

每一个进程维护了一份自己的文件描述符表,该表中的每条记录维护了该条文件描述符的相关信息,包括:

  • 控制标志(fd flags), 截至目前,内核仅定义了一个flag,close-on-exec
  • open file ptr : 指向open file table的指针

打开文件表(open file table)

内核内维护的一个系统范围的打开文件表。该表中包含每一个打开的文件条目,文件表项跟踪所有对文件的读或写操作当前偏移量和文件的打开模式(O_RDONLYO_WRONLY, or O_RDWR)。

该表中的每条记录维护了与一个打开的文件相关的全部信息,包括:

  • 文件偏移量(file offset):调用read()或者write()操作更新,调用fseek()直接修改,流类型的文件(比如pipes 和 sockets)不能使用偏移量,因为文件中的数据不是随机访问的。
  • 访问模式(status flags):只读,只写或读写等
  • inode指针:指向inode表元素的指针,关联物理文件
  • 引用计数:比如一条记录被2个文件描述符引用,计数就为2

inode表

在linux系统中使用inode号描述文件,就像进程使用pid描述进程一样。inode存储了文件的元信息。系统上的所有文件都分配了一个inode记录。

每个inode记录包含以下信息(可以使用stat命令查看):

$ stat aFile: aSize: 4           Blocks: 8          IO Block: 4096   regular file
Device: 805h/2053d  Inode: 1446030     Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/zhangboqi)   Gid: ( 1000/zhangboqi)
Access: 2021-09-29 14:35:32.344894535 +0800
Modify: 2021-09-29 14:35:32.344894535 +0800
Change: 2021-09-29 14:35:32.344894535 +0800Birth: -
  • 文件的字节数(Size):
  • Blocks: 文件占用块大小,单位512字节,就是文件实际占用大小
  • IO Block: 文件系统每次IO操作的最小大小,ext4默认是4096字节
  • 文件类型:如,常规文件(regular file),目录,套接字或FIFO等
  • 设备号(Device):设备号
  • inode号(Inode):文件对应的inode号
  • 硬链接数(Links):即有多少个文件指向这个inode
  • 文件权限(Access)
  • 文件uid和gid:
  • 文件的时间戳:Access为文件上一次打开的时间,Modify为文件上一次修改的时间,Change为inode上一次变动的时间

注:inode存储在磁盘设备上,但内核会在内存中维护一份。这里的inode table就是指内存中的副本。inode table中的记录同样维护了一个引用计数,该记录每被open file记录引用一次就加1。

文件描述符数量限制

进程可用的文件描述符的数量由sys/limits.h文件中的/OPEN_MAX控制。文件描述符的数量也可由ulimit -n控制。可以分配给进程的文件描述符的数量由资源限制控制。默认值是在/etc/security/limits文件中设置的,通常设置为2000。可以通过ulimit命令或setrlimit子例程更改该限制。最大大小由常量OPEN_MAX定义。

文件描述符的创建

open, pipe, createfcntl子程序都可以创建文件描述符。文件描述符在每个进程里都是唯一的,但是他们可以有fork子程序创建的子进程共享。也可以由fcntldupdup2子程序复制。

文件描述符是一个存储在内核为每个进程维护的u_block区域中的文件描述符表的索引。进程获取文件描述符的最常见方法是通过opencreate操作,或者从父进程继承。当一个fork操作发生时。系统为子进程复制父进程的文件描述符表,它允许子进程平等地访问父进程使用的文件。

管理文件描述符

因为文件是可以同时被多个用户共享的,所以有必要允许相关进程共享一个公共偏移指针,并且访问同一文件的独立进程拥有一个单独的当前偏移指针,open file table 条目维护了一个引用计数,用来跟踪分配给文件的文件描述符的数量。

对单个文件的多个引用可能是由下列任何一种情况引起的:

  • 打开文件的单独进程
  • 子进程保留分配给父进程的文件描述符
  • fcntl或dup子例程创建一个文件描述符的副本

共享打开文件

每个打开操作创建一个系统打开文件表项。单独的表项确保每个进程有单独的当前I/O偏移量。独立偏移量可以保护数据的完整性。当一个文件描述符被复制时,两个进程将共享相同的偏移量,并可能发生交错,在这种情况下,字节不是按顺序读或写的。

复制文件描述符

文件描述符可以通过以下方式在进程之间复制:dupdup2子例程、fork子例程和fcntl(文件描述符控制)子例程。

dup和dup2子程序

dup子例程创建一个文件描述符的副本。副本是在包含原始描述符的用户文件描述符表中的空白位置创建的。dup进程将open file table项中的引用计数加1,并返回副本所在的文件描述符的索引号。

fork子程序

fork子例程创建一个子进程,子进程继承分配给父进程的文件描述符。然后子进程执行一个新进程。当fcntl子程序关闭时继承的文件描述符会设置close-on-exec标志

FCNTL(文件描述符控制)子程序

fcntl子例程操作文件结构并控制打开的文件描述符。它可以用来对描述符进行以下更改:

  • 复制一个文件描述符(与dup子例程相同)。
  • 获得或设置“close-on-exec ”标志。
  • 为描述符设置非阻塞模式。
  • Append future writes to the end of the file(O_APPEND).
  • 当可以进行I/O时,允许向进程生成信号。
  • Set or get the process ID or the group process ID for SIGIO handling.
  • 关闭所有文件描述符。

预设文件描述符值

当shell运行一个程序时,它会打开三个文件,其中包含文件描述符0、1和2。这些描述符的默认赋值如下:

Descriptor

Explanation

0 Represents standard input.
1 Represents standard output.
2 Represents standard error.

这些默认的文件描述符连接到终端,因此,如果程序读取文件描述符0并写入文件描述符1和2,则程序从终端收集输入并将输出发送到终端。当程序使用其他文件时,文件描述符按升序分配。

如果使用<(小于)或>(大于)符号重定向I/O,则shell的默认文件描述符分配将被更改。例如,以下命令将文件描述符0和1的默认赋值从终端更改为适当的文件:

prog < FileX > FileY

在这个例子中,文件描述符0现在指的是FileX,文件描述符1指的是FileY。文件描述符2没有被更改。程序不需要知道它的输入来自哪里,也不需要知道它被发送到哪里,只要文件描述符0表示输入文件,1和2表示输出文件。

下面的示例程序演示了标准输出的重定向:

#include <fcntl.h>
#include <stdio.h>void redirect_stdout(char *);main()
{printf("Hello world\n");       /*this printf goes to* standard output*/fflush(stdout);redirect_stdout("foo");        /*redirect standard output*/printf("Hello to you too, foo\n");/*printf goes to file foo */fflush(stdout);
}void
redirect_stdout(char *filename)
{int fd;if ((fd = open(filename,O_CREAT|O_WRONLY,0666)) < 0)/*open a new file */{perror(filename);exit(1);}close(1);                       /*close old */*standard output*/if (dup(fd) !=1)                /*dup new fd to*standard input*/{fprintf(stderr,"Unexpected dup failure\n");exit(1);}close(fd);                       /*close original, new fd,*/* no longer needed*/
}

在文件描述符表中,文件描述符编号被分配到请求描述符时可用的最低描述符编号。但是,可以使用dup子例程在文件描述符表中分配任何值。

linux系统文件描述符详解相关推荐

  1. Linux文件描述符详解

    文章目录 一.概念 `1.1.特点` 优点 缺点 二.手动创建文件描述符 `2.1.语法` 2.1.1.创建 2.1.2.调用 2.1.3.关闭 `2.2.重定向输出的文件描述符` `2.3.重定向输 ...

  2. USB的端点描述符详解-重新排版

    USB的端点描述符详解 端点描述符,是描述USB通信通道或管道的类型和功能的标准USB描述符. 端点描述符和接口描述符还有配置描述符一样,不能单独发送给USB主机,需要以配置描述符集合的形式发送给主机 ...

  3. (USB系列三)stm32 CubeMX usb音频描述符详解 usb audio UAC

    如果需要麦克风阵列,回声消除,声源定位,波束成形,语音对话的产品请访问我好朋友的店铺. 店铺链接:首页-智能语音开发者联盟-淘宝网 大家好我是人见人爱.花见花开的大魔王. usb协议还是很烦的,cub ...

  4. python描述符详解_Python描述符 (descriptor) 详解

    1.什么是描述符? python描述符是一个"绑定行为"的对象属性,在描述符协议中,它可以通过方法重写属性的访问.这些方法有 __get__(), __set__(), 和__de ...

  5. python 描述符参考文档_python 描述符详解

    Python中包含了许多内建的语言特性,它们使得代码简洁且易于理解.这些特性包括列表/集合/字典推导式,属性(property).以及装饰器(decorator).对于大部分特性来说,这些" ...

  6. python描述符详解

    什么是描述符 数据描述符data descriptor和非数据描述符non-data descriptors 如何检测一个对象是不是描述符 描述符有什么用和好处 例子 总结 本文主要介绍描述符的定义, ...

  7. USB HID设备报告描述符详解

    概述: 报告在这里意思是数据传输(data transfer),而报告描述符是对这些传输的数据作用途(usage)上的说明. USB通讯协议的规范是以1ms产生一个USB帧(Frame),USB设备可 ...

  8. linux文件编程(2)——系统文件描述符、动静态文件、块设备介绍

    参考:linux文件编程(2)--文件操作原理简述之文件描述符.动静态文件.块设备 作者:丶PURSUING 发布时间: 2021-04-09 11:14:12 网址:https://blog.csd ...

  9. linux换行符 r,\r \n 回车换行符详解

    \r \n 回车换行符详解 \r \n 回车换行符详解 \r \n 回车换行符详解1. \r \n 回车换行的含义1.1 \r 回车 1.2 \n 换行 2. \r \n 回车换行的历史2.1 \r ...

最新文章

  1. jQuery插件开发 - 其实很简单
  2. k8s 下线node正确处理姿势
  3. linux命令——tar
  4. Citrix Reciever更改https为http模式
  5. 网页后门工具laudanum
  6. apache-spark导入eclipse环境
  7. php 情书,PHP好玩的代码一(笛卡尔的情书)
  8. Java文件路径及文件名乱码_javaweb文件下载及文件名中文乱码处理
  9. 申请加入了sharepoint团队
  10. R语言 支持向量机分类预测
  11. 1、win10下的Docker+Redis 的下载及简单使用
  12. 微博app打开微信小程序的方法
  13. Android 获取手机存储总大小,系统占用空间
  14. java静态变量、静态方法、代码块、main方法
  15. partition by用法
  16. mysql checking_高并发下MySQL出现checking permissions
  17. 读王竹峰老师 《一个数据库十年老兵的思考与总结》 有感
  18. 英飞凌TRAVEO II介绍
  19. Web前端框架学习—Bootstrap
  20. python画一朵玫瑰花,制作成可执行文件

热门文章

  1. kafka报错:InvalidReceiveException: Invalid receive (size = 1195725856 larger than 104857600)
  2. 测试设备硬件项目开发流程
  3. 微软TECH-ED2010门票到手
  4. Head First 设计模式笔记 5.命令模式
  5. 羊了个羊1.0(第一关)
  6. Unity3d(PlayerPrefs 类的介绍与使用)
  7. RC4加密解密算法123
  8. mt管理器用sh文件双开应用(多开)
  9. 滴滴顺风车公布产品方案向公众征求意见,上线仍无具体时间
  10. TDD测试驱动开发一