Dans le système Linux, tout peut être considéré comme un fichier, et les fichiers peuvent être divisés en : fichiers ordinaires, fichiers de répertoire, fichiers de lien et périphérique. fichiers. Un descripteur de fichier est un index créé par le noyau afin de gérer efficacement les fichiers ouverts. Il s'agit d'un entier non négatif (généralement un petit entier) utilisé pour faire référence au fichier ouvert. Toutes les opérations d'E/S sont effectuées. parcourir les descripteurs de fichiers. Lorsque le programme est démarré pour la première fois, 0 est l'entrée standard, 1 est la sortie standard et 2 est l'erreur standard. Si vous ouvrez un nouveau fichier à ce moment-là, son descripteur de fichier sera 3.
Opérations de descripteur de fichier (telles que : open(), creat(), close(), read())) le retour est un descripteur de fichier, qui est un entier de type int, c'est-à-dire fd. Son essence est l'indice dans la table des descripteurs de fichier. Il agit comme un index. Le processus trouve le fd via la table des descripteurs de fichier dans le PCB. pointeur pointé par filp. Chaque processus stocke une table de descripteurs de fichiers dans le PCB (Process Control Block), qui est le bloc de contrôle de processus. Le descripteur de fichier est l'index de cette table. Chaque entrée de la table de description de fichier a un pointeur vers le fichier ouvert. le fichier ouvert est représenté par la structure file
dans le noyau, et le pointeur dans le tableau des descripteurs de fichier pointe vers la structure file
. Chaque fois qu'un fichier est ouvert, fd est alloué par défaut en commençant par le plus petit index inutilisé. Inconvénients des descripteurs de fichiers : ils ne peuvent pas être portés sur des systèmes autres qu'UNIX, et ils ne sont pas intuitifs.
Dessinez une image ci-dessous pour montrer la relation entre eux :
Et chaque fichier contient principalement les informations suivantes :
maintient l'indicateur d'état du fichier (file
membre de la structure file
) et la position actuelle de lecture et d'écriture (f_flags
membre de la structure file
) dans la structure f_pos
. Dans la figure ci-dessus, les processus 1 et 2 ouvrent le même fichier, mais correspondent à des structures file
différentes, ils peuvent donc avoir des indicateurs d'état de fichier et des emplacements de lecture et d'écriture différents. Les membres les plus importants de la structure file
sont également f_count
, qui représente le nombre de références. Nous en reparlerons plus tard. Les appels système tels que dup
et fork
feront pointer plusieurs descripteurs de fichiers vers le même. file
structure, par exemple, fd1
et fd2
font référence à la même structure file
, alors son nombre de références est 2. Lorsque close(fd1)
est utilisé, la structure file
ne sera pas publiée, mais Réduisez uniquement le nombre de références à 1. Si vous close(fd2)
à nouveau, le nombre de références sera réduit à 0 et la structure file
sera libérée. Cela fermera en fait le fichier.
Chaque structure file
pointe vers une structure file_operations
Les membres de cette structure sont des pointeurs de fonction, pointant vers des fonctions du noyau qui implémentent diverses opérations sur les fichiers. Par exemple, dans un programme utilisateur, read
a un descripteur de fichier, read
entre dans le noyau via un appel système, puis trouve la structure file
pointée par le descripteur de fichier, et trouve la structure file
pointée vers par la structure file_operations
, appelez la fonction noyau pointée par son membre read
pour compléter la demande de l'utilisateur. Lorsque des fonctions telles que lseek
, read
, write
, ioctl
, open
sont appelées dans le programme utilisateur, le noyau finira par appeler la fonction noyau pointée par chaque membre de file_operations
pour terminer le demande de l'utilisateur. Le membre file_operations
dans la structure release
est utilisé pour compléter la requête close
du programme utilisateur. La raison pour laquelle il est appelé release
au lieu de close
est qu'il ne ferme pas nécessairement le fichier, mais. réduit le nombre de références. Le fichier est fermé uniquement lorsque le nombre de références tombe à 0. Pour les fichiers normaux ouverts sur le même système de fichiers, les étapes et méthodes d'opérations sur les fichiers telles que read
et write
doivent être les mêmes, et les fonctions appelées doivent être les mêmes, donc les trois fichiers ouverts dans la figure structure pointe vers la même file
structure. Si vous ouvrez un fichier de périphérique de caractères, alors ses opérations file_operations
et read
sont définitivement différentes des fichiers normaux. Elles ne lisent et n'écrivent pas de blocs de données sur disque mais lisent et écrivent des périphériques matériels, donc la structure write
doit pointer vers. file
Structure différente, diverses fonctions d'exploitation de fichiers sont implémentées par le pilote de l'appareil. file_operations
Chaque structure file
a un pointeur vers la structure dentry
"dentry" est l'abréviation d'entrée de répertoire. Les paramètres que nous transmettons aux fonctions telles que open
et stat
sont un chemin, tel que /home/akaedu/a
, et l'inode du fichier doit être trouvé en fonction du chemin. Afin de réduire le nombre de lectures sur le disque, le noyau met en cache la structure arborescente du répertoire, appelée cache dentry, dans laquelle chaque nœud est une structure dentry
. Il suffit de rechercher le dentry le long de chaque partie du chemin, en commençant par le. répertoire racine /
Recherchez le répertoire home
, puis le répertoire akaedu
, puis le fichier a
. Le cache dentry enregistre uniquement les entrées de répertoire récemment consultées. Si l'entrée de répertoire que vous recherchez ne se trouve pas dans le cache, elle doit être lue depuis le disque dans la mémoire.
Chaque dentry
structure possède un pointeur pointant vers la structure inode
. inode
La structure stocke les informations lues à partir de l'inode du disque. Dans l'exemple ci-dessus, il y a deux entrées, représentant respectivement /home/akaedu/a
et /home/akaedu/b
. Elles pointent toutes deux vers le même inode, indiquant que les deux fichiers sont des liens physiques l'un vers l'autre. inode
La structure stocke les informations lues à partir de l'inode de la partition de disque, telles que le propriétaire, la taille du fichier, le type de fichier, les bits d'autorisation, etc. Chaque structure inode
a un pointeur vers la structure inode_operations
, qui est également un ensemble de pointeurs de fonction pointant vers certaines fonctions du noyau qui effectuent des opérations sur les répertoires de fichiers. Différent de file_operations
, ce que inode_operations
pointe n'est pas une fonction qui opère sur un certain fichier, mais une fonction qui affecte la disposition des fichiers et des répertoires, comme l'ajout et la suppression de fichiers et de répertoires, le suivi des liens symboliques, etc. , qui appartiennent au même système de fichiers. Chaque structure inode
peut pointer vers la même structure inode_operations
. La structure
inode
a un pointeur vers la structure super_block
. super_block
La structure stocke les informations lues à partir du super bloc de la partition de disque, telles que le type de système de fichiers, la taille du bloc, etc. Le membre super_block
de la structure s_root
est un pointeur vers dentry
, indiquant où se trouve le répertoire racine du système de fichiers mount
. Dans l'exemple ci-dessus, la partition est mount
vers le répertoire /home
. . Vers le bas.
file
, dentry
, inode
, super_block
Ces structures forment le concept de base de VFS (Virtual File System VFS, Virtual Filesystem).
(1). Afficher les descripteurs de fichiers Linux
1 [root@localhost ~]# sysctl -a | grep -i file-max --color 3 fs.file-max = 392036 5 [root@localhost ~]# cat /proc/sys/fs/file-max 7 392036 9 [root@localhost ~]# ulimit -n11 102413 [root@localhost ~]#
Le descripteur de fichier maximum sous Linux Il y a deux aspects. Parmi les restrictions, l'une concerne les restrictions au niveau de l'utilisateur et l'autre les restrictions au niveau du système.
Restrictions au niveau du système : les valeurs affichées dans la commande sysctl et dans le système de fichiers proc sont les mêmes. Il s'agit d'une restriction au niveau du système. C'est la somme des restrictions sur les fichiers ouverts. descripteurs pour tous les utilisateurs
Restrictions au niveau de l'utilisateur : ce que la commande ulimit voit est la limite maximale des descripteurs de fichiers au niveau de l'utilisateur, ce qui signifie que le nombre total de descripteurs de fichiers occupés par les programmes exécutés après que chaque utilisateur se connecte ne peut pas dépasser cette limite
(2 Modifier la valeur du descripteur de fichier
1 [root@localhost ~]# ulimit-SHn 102402 [root@localhost ~]# ulimit -n3 102404 [root@localhost ~]#
La modification ci-dessus n'affecte que le). session en cours et est temporaire S'il doit être modifié de manière permanente, vous devez le modifier comme suit :
1 [root@localhost ~]# grep -vE'^$|^#' /etc/security/limits.conf2 * hard nofile 40963 [root@localhost ~]#
1 //默认配置文件中只有hard选项,soft 指的是当前系统生效的设置值,hard 表明系统中所能设定的最大值2 [root@localhost ~]# grep -vE'^$|^#' /etc/security/limits.conf3 * hard nofile 102404 * soft nofile 102405 [root@localhost ~]#6 // soft<=hard soft的限制不能比hard限制高
(3) . Modifier les restrictions du système
1 [root@localhost ~]# sysctl -wfs.file-max=4000002 fs.file-max = 4000003 [root@localhost ~]# echo350000 > /proc/sys/fs/file-max //重启后失效4 [root@localhost ~]# cat /proc/sys/fs/file-max5 3500006 [root@localhost ~]#
//Ce qui précède est une modification temporaire du descripteur de fichier
//Modification permanente, ajoutez fs.file-max=400000 à /. etc/sysctl.conf, utilisez sysctl -p
et ouvre le /home/shenlan/hello.c fichier. S'il n'y a pas de fichier hello.c dans ce répertoire, le programme est automatiquement créé et le descripteur de fichier renvoyé dans le programme est 3. Parce que lorsque le processus démarre, trois fichiers, entrée standard (0), sortie standard (1) et traitement des erreurs standard (2) , sont ouverts par défaut, fd commence à être alloué à partir du plus petit index inutilisé. , donc le descripteur de fichier renvoyé est 3.
1 #include<stdio.h> 2 #include<sys/types.h> 3 #include<sys/stat.h> 4 #include<fcntl.h> 5 #include<stdlib.h> 6 int main() 7 { 8 int fd; 9 if((fd = open("/home/shenlan/fd.c",O_CREAT|O_WRONLY|O_TRUNC,0611))<0){10 perror("openfile fd.c error!\n");11 exit(1);12 }13 else{14 printf("openfile fd.c success:%d\n",fd);15 }16 if(close(fd) < 0){17 perror("closefile fd.c error!\n");18 exit(1);19 }20 else21 printf("closefile fd.c success!\n");22 exit(0);23 }
执行结果:
进程通过系统调用open( )来打开一个文件,实质上是获得一个文件描述符,以便进程通过文件描述符为连接对文件进行其他操作。进程打开文件时,会为该文件创建一个file对象,并把该file对象存入进程打开文件表中(文件描述符数组),进而确定了所打开文件的文件描述符。 open( )操作在内核里通过sys_open( )实现的,sys_open( )将创建文件的dentry、inode和file对象,并在file_struct结构体的进程打开文件表fd_array[NR_OPEN_DEFAULT]中寻找一个空闲表项,然后返回这个表项的下标(索引),即文件描述符。创建文件的file对象时,将file对象的f_op指向了所属文件系统的操作函数集file_operations,而该函数集又来自具体文件的i节点,于是虚拟文件系统就与实际文件系统的操作衔接起来了。
C语言中使用的是文件指针而不是文件描述符做为I/O的句柄."文件指针(file pointer)"指向进程用户区中的一个被称为FILE结构的数据结构。FILE结构包括一个缓冲区和一个文件描述符值.而文件描述符值是文件描述符表中的一个索引.从某种意义上说文件指针就是句柄的句柄。流(如: fopen)返回的是一个FILE结构指针, FILE结构是包含有文件描述符的,FILE结构函数可以看作是对fd直接操作的系统调用的封装, 它的优点是带有I/O缓存。
从文件描述符fd 到文件流 FILE* 的函数是
FILE* fdopen(int filedes,const char* mode);
早期的C标准库中,FILE在stdio.h中定义;Turbo C中,参见谭浩强的《C程序设计》,FILE结构体中包含成员fd,即文件描述符。亦可以在安装的Ubuntu系统的/usr/include/stdio.h中找到struct _IO_FILE结构体,这个结构体比较复杂,我们只关心需要的部分-文件描述符,但是在这个的结构体中,我们并没有发现与文件描述符相关的诸如fd成员变量。此时,类型为int的_fileno结构体成员引起了我们的注意,但是不能确定其为文件描述符。因此写个程序测试是最好的办法,可以用以下的代码测试:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<sys/types.h> 4 #include<sys/stat.h> 5 #include<fcntl.h> 6 int main( ) 7 { 8 char buf[50] = {"ILOVE this game!"}; 9 FILE *myfile;10 11 myfile = fopen("2.txt","w+");12 if(!myfile){13 printf("error:openfile failed!\n");14 }15 printf("The openedfile's descriptor is %d\n",myfile->_fileno);16 if(write(myfile->_fileno,buf,50)< 0){17 perror("error:writefile failed!\n");18 exit(1);19 }else{20 printf("writefile successed!\n");21 }22 exit(0);23 }
, utilisez la fonction fopen pour ouvrir le fichier 2.txt en lecture et en écriture si le fichier 2.txt. n'existe pas, créez ce document. Et il renvoie le pointeur FILE myfile. Utilisez printf pour imprimer la valeur de myfile->_fileno sur un terminal standard et transmettez myfile->_fileno comme descripteur de fichier à write Appel système pour écrire les données du tampon dans le fichier ouvert. Utilisez ensuite la commande cat pour afficher le contenu de 2.txt. Le résultat de l'exécution est affiché sur la figure. La valeur de _fileno est 3 car l'entrée, la sortie et les erreurs standard sont 0, 1, 2. Le résultat de sortie est le suivant :
Par conséquent, le membre _fileno est le handle (système windows) ou le descripteur de fichier renvoyé par le système d'exploitation lors de l'ouverture. le fichier. Pour une étude approfondie, vous pouvez lire « CStandard Library » publiée par People's Posts and Telecommunications Publishing House. Bien entendu, vous pouvez également lire le fichier /glibc-2.9/manual/io.txti. Linux, l'allocation du descripteur de fichier consiste à vérifier si le descripteur de fichier a été utilisé un par un de petit à grand, puis à l'allouer. Vous pouvez également écrire un programme à tester.
La table des descripteurs de fichiers est également appelée tableau de descripteurs de fichiers , qui stocke tous les fichiers ouverts par un processus. Le tableau de descripteurs de fichier est contenu dans la structure file tablefiles_struct ouverte par le processus. est défini dans /include/linux/fdtable.h et est un tableau de pointeurs pointant vers le fichier type ---fd_array[NR_OPEN_DEFAULT], où NR_OPEN_DEFAULT est également défini dans fdtable.h Il s'agit d'une variable liée à l'architecture spécifique du CPU, #define NR_OPEN_DEFAULTBITS_PER_LONG.
FICHIER structure La relation entre le descripteur de fichier et la structure du fichier peut être représentée par la figure suivante :
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!