专栏首页技术小黑屋解读文件描述符

解读文件描述符

最近由于机缘巧合,结合最近工作中遇到的一些问题,深入了解了文件描述符(File Descriptor,简称FD,以下使用 FD 称谓)。预计会有两到三篇关于 FD 的文章陆续出来。首篇也就是这篇,作为基础篇,介绍一些关于通用 FD 的内容知识。

概念定义

  • 文件描述符 是 用来访问资源(文件,输入输出设备等)的一种抽象指示符。
  • 文件描述符 是POSIX(Portable Operating System Interface)规范的组成部分
  • 文件描述符 通常是非负整数,C 语言中使用int类型。

FD 具体可以指向什么

  • 文件/目录 files/directories
  • 输入输出源 input/output
  • 管道 pipes
  • 套接字 sockets
  • 其他 Unix 文件类型 other Unix files

系统默认的FDs

每一个 Unix 进程中,通常会有三个预制的 FD。它们分别是

  • 标准输入 Standard input
  • 标准输出 Standard output
  • 标准错误(输出) Standard error

其对应的行为是

  • 标准输入 用于程序接受数据
  • 标准输出 用于程序输出数据
  • 标准错误 用于程序输出错误或者诊断信息

内部机制

三张表

如上图从左至右有三张表

  • file descriptor table 归属于单个进程
  • global file table(又称open file table) 归属于系统全局
  • inode table 归属于系统全局

从一次文件打开说起

当我们尝试打开文件/path/myfile.txt

1.从inode table 中查找到对应的文件节点 2.根据用户代码open的一些参数(比如读写权限等)在open file table 中创建open file 节点 3.将上一步的open file节点信息保存,在file descriptor table中创建 file descriptor 4.返回上一步的file descriptor的索引位置,供应用读写等使用。

备注:上述图片来自https://www.computerhope.com/jargon/f/file-descriptor.htm

FD 数量限制

出于稳定系统性能和避免因为过多打开文件导致CPU和RAM占用居高的考虑,系统都会设置了一个最大可用的 FD 数量。

FD上限值通常不小,一般应用很难达到。

限制类型

  • hard limit 由系统管理权限人员设定,是soft limit 可以设置的上限
  • soft limit 当前用户设置,用来限定进程,通常小于(但不能超过)hard limit值。

1 2 3 4 5 6 7 8

#查看soft limit 设置 ➜ /tmp ulimit -nS 4864 #查看 hard limit 设置 ➜ /tmp ulimit -nH unlimited

Questions

进程退出与 FD 关系

因为file descriptor table 存在于 PCB (进程控制块,Process Control Block) 中,进程退出后所有的 FD都需要关闭处理掉。

如下为POSIX文档

All of the file descriptors, directory streams, conversion descriptors, and message catalog descriptors open in the calling process shall be closed.

同一路径 与 FD 关系

  • 同一文件,多次打开,FD值不同
  • 同一文件,读写模式不同打开,FD值也不同

打开文件过多会怎样

  • open返回值会出现-1
  • 通常会导致进程无法进行,甚至是崩溃

示例验证代码

如下代码可以验证上述问题中的结论

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71

#include<stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> void printStandardFD() { //input/output/error stream printf("%d\t\t\t%p\t\t\t Terminal's input device\n", STDIN_FILENO, stdin); printf("%d\t\t\t%p\t\t\t Terminal's output device\n", STDOUT_FILENO,stdout); printf("%d\t\t\t%p\t\t\t Terminal's error device\n", STDERR_FILENO, stderr); } int printInputFD() { int afd = open("/tmp/a.txt", O_RDONLY); if (afd == -1 ) { printf("error occurs %s\n", strerror(errno)); } printf("%d\t\t\t %p\t\t\t File /tmp/a.txt\n", afd, fdopen(afd, "r")); return afd; } void printWriteFD() { int fd = open("/tmp/b.txt", O_WRONLY); printf("%d\t\t\t %p\t\t\t File /tmp/b.txt\n", fd, fdopen(fd, "w")); } void testSamePathDifferentMode() { int readFd = open("/tmp/c.txt", O_RDONLY); printf("%d\t\t\t %p\t\t\t File /tmp/c.txt read \n", readFd, fdopen(readFd, "r")); int writeFd = open("/tmp/c.txt", O_WRONLY); printf("%d\t\t\t %p\t\t\t File /tmp/c.txt write \n", writeFd, fdopen(writeFd, "w")); } void printPipeFD() { int pipeFds[2]; pipe(pipeFds); printf("%d\t\t\t %p\t\t\t Pipe's read end\n", pipeFds[0], fdopen(pipeFds[0], "r")); printf("%d\t\t\t %p\t\t\t Pipe's write end\n", pipeFds[1], fdopen(pipeFds[1], "w")); } void tryToReachMaxFDs() { while(1 == 1) { if(-1 == printInputFD()) { break; } } } void scanChars() { char chr; printf("Enter a character: "); scanf("%c",&chr); } int main(){ printf("Process File Descriptor table\n"); printf("-----------------------------------------------------\n"); printf("Descriptor\t\t Pointer\t\t Description\n"); printStandardFD(); printInputFD(); printWriteFD(); //printPipeFD(); //tryToReachMaxFDs(); //testSamePathDifferentMode(); scanChars(); }

P.S.很多年不写C代码了。

References

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 用好 Require,check,assert,写好 Kotlin 代码

    在编码的时候,我们需要做很多的检测判断,比如某个变量是否为null,某个成员属性是否为true,执行某个操作结果是否成功。比如像下面的这段代码

    技术小黑屋
  • 未关闭的文件流会引起内存泄露么?

    最近接触了一些面试者,在面试过程中有涉及到内存泄露的问题,其中有不少人回答说,如果文件打开后,没有关闭会导致内存泄露。当被继续追问,为什么会导致内存泄露时,大部...

    技术小黑屋
  • Auth Password Cannot Be Read From a File

    I am facing this problem which leaves the error message

    技术小黑屋
  • 1050. 螺旋矩阵(25)

    本题要求将给定的N个正整数按非递增的顺序,填入“螺旋矩阵”。所谓“螺旋矩阵”,是指从左上角第1个格子开始,按顺时针螺旋方向填充。要求矩阵的规模为m行n列,满足条...

    AI那点小事
  • linux常用命令之压缩打包用法选项DEMO注意选项DEMO用法选项用法选项DEMO

    DF df – report file system disk space usage 查看文件系统的使用清空 用法 df [-hi] [path]选项-h h...

    用户1174983
  • 子集

    给定一组不含重复元素的整数数组nums,返回该数组所有可能的子集(幂集)。 说明:解集不能包含重复的子集。

    WindrunnerMax
  • 基于Socket.IO实现Android聊天功能代码示例

    Socket.IO是一个完全由JavaScript实现、基于Node.js、支持WebSocket的协议用于实时通信、跨平台的开源框架,它包括了客户端的Java...

    砸漏
  • left join on and 与 left join on where的区别

    数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户。

    wuweixiang
  • MySQL Table doesn’t exist in engine 解决方法

    数据表设置了外键,在phpMyAdmin中显示该表使用中,点击访问表时提示Table doesn’t exist in engine。 mysql日志显示:

    TLingC
  • 【全网首发】机器学习该如何应用到量化投资系列(三)

    有一些单纯搞计算机、数学或者物理的人会问,究竟怎么样应用 ML 在量化投资。他们能做些什么自己擅长的工作。虽然在很多平台或者自媒体有谈及有关的问题,但是不够全面...

    量化投资与机器学习微信公众号

扫码关注云+社区

领取腾讯云代金券