最近由于机缘巧合,结合最近工作中遇到的一些问题,深入了解了文件描述符(File Descriptor,简称FD,以下使用 FD 称谓)。预计会有两到三篇关于 FD 的文章陆续出来。首篇也就是这篇,作为基础篇,介绍一些关于通用 FD 的内容知识。
每一个 Unix 进程中,通常会有三个预制的 FD。它们分别是
其对应的行为是
如上图从左至右有三张表
当我们尝试打开文件/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
出于稳定系统性能和避免因为过多打开文件导致CPU和RAM占用居高的考虑,系统都会设置了一个最大可用的 FD 数量。
FD上限值通常不小,一般应用很难达到。
1 2 3 4 5 6 7 8 | #查看soft limit 设置 ➜ /tmp ulimit -nS 4864 #查看 hard limit 设置 ➜ /tmp ulimit -nH unlimited |
---|
因为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.
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代码了。