Einführung in das Konzept von Dateideskriptoren und FILE

PHP中文网
Freigeben: 2017-06-21 13:44:23
Original
3206 Leute haben es durchsucht

1. Dateideskriptor (Schlüsselpunkt)

Im Linux-System kann alles als Datei betrachtet werden und Dateien können unterteilt werden in: normale Dateien, Verzeichnisdateien, Linkdateien und Geräte Dateien. Ein Dateideskriptor ist ein vom Kernel erstellter Index, um offene Dateien effizient zu verwalten. Es handelt sich um eine nicht-negative Ganzzahl (normalerweise eine kleine Ganzzahl), die zum Verweisen auf die geöffnete Datei verwendet wird Gehen Sie die Dateideskriptoren durch. Beim ersten Start des Programms ist 0 die Standardeingabe, 1 die Standardausgabe und 2 der Standardfehler. Wenn Sie zu diesem Zeitpunkt eine neue Datei öffnen, lautet der Dateideskriptor 3.

1.1 Einführung in das Konzept

Dateideskriptoroperationen (z. B. open(), creat(), close(), read())) werden zurückgegeben Ein Dateideskriptor, der eine Ganzzahl vom Typ int ist, d. h. fd. Sein Wesen ist der Index in der Dateideskriptortabelle. Der Prozess findet den fd in der Datei Zeiger, auf den filp zeigt. Jeder Prozess speichert eine Dateideskriptortabelle im PCB (Prozesskontrollblock). Der Dateideskriptor ist der Index dieser Tabelle. Jeder Eintrag in der Dateibeschreibungstabelle hat einen Zeiger auf die geöffnete Datei. Die geöffnete Datei wird durch die Struktur file im Kernel dargestellt, und der Zeiger in der Dateideskriptortabelle zeigt auf die Struktur file. Jedes Mal, wenn eine Datei geöffnet wird, wird fd standardmäßig beginnend mit dem kleinsten nicht verwendeten Index zugewiesen. Nachteile von Dateideskriptoren: Sie können nicht auf andere Systeme als UNIX portiert werden und sind nicht intuitiv.

Zeichnen Sie unten ein Bild, um die Beziehung zwischen ihnen zu zeigen:

Und jede Datei enthält hauptsächlich die folgenden Informationen:

1.2 Diagrammerklärung

verwaltet das Dateistatus-Flag (file Mitglied der Struktur file) und die aktuelle Lese- und Schreibposition (f_flags Mitglied der Struktur file) in der f_pos-Struktur. In der Abbildung oben öffnen sowohl Prozess 1 als auch Prozess 2 dieselbe Datei, entsprechen jedoch unterschiedlichen file-Strukturen, sodass sie unterschiedliche Dateistatus-Flags sowie Lese- und Schreiborte haben können. Die wichtigeren Mitglieder der file-Struktur sind auch f_count, die den Referenzzähler darstellen. Wir werden später darüber sprechen, dass Systemaufrufe wie dup und fork dazu führen, dass mehrere Dateideskriptoren auf dieselben verweisen file Struktur, zum Beispiel beziehen sich sowohl fd1 als auch fd2 auf dieselbe file Struktur, dann ist ihr Referenzzähler 2. Wenn close(fd1) verwendet wird, wird die file Struktur nicht freigegeben, aber Reduzieren Sie nur den Referenzzähler auf 1. Wenn Sie erneut close(fd2) ausführen, wird der Referenzzähler auf 0 reduziert und die file-Struktur freigegeben. Dadurch wird die Datei tatsächlich geschlossen.

Jede file-Struktur zeigt auf eine file_operations-Struktur. Die Mitglieder dieser Struktur sind Funktionszeiger, die auf Kernelfunktionen verweisen, die verschiedene Dateioperationen implementieren. Beispielsweise hat read in einem Benutzerprogramm einen Dateideskriptor, read gelangt über einen Systemaufruf in den Kernel, findet dann die file-Struktur, auf die der Dateideskriptor zeigt, und findet die file-Struktur, auf die gezeigt wird Rufen Sie anhand der file_operations-Struktur die Kernelfunktion auf, auf die ihr read-Mitglied verweist, um die Benutzeranforderung abzuschließen. Wenn Funktionen wie lseek, read, write, ioctl, open im Benutzerprogramm aufgerufen werden, ruft der Kernel schließlich die Kernelfunktion auf, auf die jedes Mitglied von file_operations zeigt, um den Vorgang abzuschließen Benutzerwunsch. Der file_operations-Member in der release-Struktur wird verwendet, um die close-Anfrage des Benutzerprogramms abzuschließen. Der Grund, warum er release anstelle von close heißt, liegt darin, dass er die Datei nicht unbedingt schließt reduziert den Referenzzähler. Die Datei wird nur geschlossen, wenn der Referenzzähler auf 0 fällt. Für reguläre Dateien, die im selben Dateisystem geöffnet werden, sollten die Schritte und Methoden von Dateioperationen wie read und write gleich sein und die aufgerufenen Funktionen sollten gleich sein, sodass die drei geöffneten Dateien in der Abbildung -Struktur verweist auf dieselbe file-Struktur. Wenn Sie eine Zeichengerätedatei öffnen, unterscheiden sich ihre Vorgänge file_operations und read definitiv von normalen Dateien. Sie lesen und schreiben keine Datenblöcke auf der Festplatte, sondern lesen und schreiben Hardwaregeräte, daher sollte die Struktur write darauf verweisen unterschiedlich fileStruktur, verschiedene darin enthaltene Dateibetriebsfunktionen werden vom Treiber des Geräts implementiert. file_operations

Jede file-Struktur hat einen Zeiger auf die dentry-Struktur. „dentry“ ist die Abkürzung für Verzeichniseintrag. Die Parameter, die wir an Funktionen wie open und stat übergeben, sind ein Pfad, wie z. B. /home/akaedu/a, und der Inode der Datei muss anhand des Pfads gefunden werden. Um die Anzahl der Festplattenlesevorgänge zu reduzieren, speichert der Kernel die Baumstruktur des Verzeichnisses, den so genannten Dentry-Cache, zwischen, in der jeder Knoten eine dentry-Struktur ist. Suchen Sie einfach entlang jedes Teils des Pfads nach dem Dentry, beginnend mit dem Stammverzeichnis / Suchen Sie das Verzeichnis home, dann das Verzeichnis akaedu und dann die Datei a. Der Dentry-Cache speichert nur zuletzt aufgerufene Verzeichniseinträge. Wenn sich der gesuchte Verzeichniseintrag nicht im Cache befindet, muss er von der Festplatte in den Speicher gelesen werden.

Jede dentry-Struktur verfügt über einen Zeiger, der auf die inode-Struktur zeigt. inodeDie Struktur speichert die vom Festplatten-Inode gelesenen Informationen. Im obigen Beispiel gibt es zwei Einträge, die jeweils /home/akaedu/a und /home/akaedu/b darstellen. Sie verweisen beide auf denselben Inode, was darauf hinweist, dass die beiden Dateien fest miteinander verknüpft sind. inodeIn der Struktur werden vom Inode der Festplattenpartition gelesene Informationen gespeichert, z. B. Eigentümer, Dateigröße, Dateityp, Berechtigungsbits usw. Jede inode-Struktur verfügt über einen Zeiger auf die inode_operations-Struktur, bei der es sich auch um eine Reihe von Funktionszeigern handelt, die auf einige Kernelfunktionen verweisen, die Dateiverzeichnisoperationen abschließen. Im Gegensatz zu file_operations verweist inode_operations nicht auf eine Funktion, die eine bestimmte Datei bearbeitet, sondern auf eine Funktion, die das Layout von Dateien und Verzeichnissen beeinflusst, z. B. das Hinzufügen und Löschen von Dateien und Verzeichnissen, das Verfolgen symbolischer Links usw. , die zum selben Dateisystem gehören. Jede inode-Struktur kann auf dieselbe inode_operations-Struktur verweisen. Die

inode-Struktur hat einen Zeiger auf die super_block-Struktur. super_blockIn der Struktur werden Informationen gespeichert, die aus dem Superblock der Festplattenpartition gelesen wurden, z. B. Dateisystemtyp, Blockgröße usw. Das super_block-Mitglied der s_root-Struktur ist ein Zeiger auf dentry und gibt an, wo sich das Stammverzeichnis des Dateisystems mount befindet. Im obigen Beispiel befindet sich die Partition mount im Verzeichnis /home . Runter.

file, dentry, inode, super_block Diese Strukturen bilden das Kernkonzept von VFS (Virtual Filesystem VFS, Virtual Filesystem).

1.3 Operationen an Dateideskriptoren

(1). Linux-Dateideskriptoren anzeigen

 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 ~]#
Nach dem Login kopieren

Der maximale Dateideskriptor unter Linux Es gibt zwei Aspekte Bei den Einschränkungen handelt es sich zum einen um Einschränkungen auf Benutzerebene und zum anderen um Einschränkungen auf Systemebene.

Einschränkungen auf Systemebene: Die im Befehl sysctl und im Dateisystem proc angezeigten Werte sind die gleichen. Es handelt sich um eine Einschränkung auf Systemebene Deskriptoren für alle Benutzer

Einschränkungen auf Benutzerebene: Was der Befehl ulimit sieht, ist das maximale Dateideskriptorlimit auf Benutzerebene, was bedeutet, dass die Gesamtzahl der Dateideskriptoren von den ausgeführten Programmen belegt wird Nachdem sich jeder Benutzer angemeldet hat, darf dieser Grenzwert nicht überschritten werden

(2) Ändern Sie den Wert des Dateideskriptors

1 [root@localhost ~]# ulimit-SHn 102402 [root@localhost ~]# ulimit  -n3 102404 [root@localhost ~]#
Nach dem Login kopieren

Die obige Änderung betrifft nur aktuelle Sitzung und ist vorübergehend. Wenn es dauerhaft geändert werden muss, müssen Sie es wie folgt ändern:

1 [root@localhost ~]# grep -vE'^$|^#' /etc/security/limits.conf2 *                hard nofile                  40963 [root@localhost ~]#
Nach dem Login kopieren
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限制高
Nach dem Login kopieren

(3) . Ändern Sie die Systemeinschränkungen

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 ~]#
Nach dem Login kopieren

//Das Obige ist eine vorübergehende Änderung des Dateideskriptors
//Permanente Änderung, fügen Sie fs.file-max=400000 zu / hinzu etc/sysctl.conf, verwenden Sie sysctl -p

1.4 Das Programm schaut sich das Programm unter dem Dateideskriptor

an und öffnet die Datei /home/shenlan/hello.c -Datei. Wenn in diesem Verzeichnis keine hello.c-Datei vorhanden ist, wird das Programm automatisch erstellt und der im Programm zurückgegebene Dateideskriptor ist 3. Denn wenn der Prozess startet, werden drei Dateien, Standardeingabe (0), Standardausgabe (1) und Standardfehlerverarbeitung (2) , geöffnet. Standardmäßig beginnt die Zuweisung von fd ab dem kleinsten nicht verwendeten Index , also ist der zurückgegebene Dateideskriptor 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 }
Nach dem Login kopieren

执行结果:

1.5进程打开一个文件的具体流程    

进程通过系统调用open( )来打开一个文件,实质上是获得一个文件描述符,以便进程通过文件描述符为连接对文件进行其他操作。进程打开文件时,会为该文件创建一个file对象,并把该file对象存入进程打开文件表中(文件描述符数组),进而确定了所打开文件的文件描述符。        open( )操作在内核里通过sys_open( )实现的,sys_open( )将创建文件的dentryinodefile对象,并在file_struct结构体的进程打开文件表fd_array[NR_OPEN_DEFAULT]中寻找一个空闲表项,然后返回这个表项的下标(索引),即文件描述符。创建文件的file对象时,将file对象的f_op指向了所属文件系统的操作函数集file_operations,而该函数集又来自具体文件的i节点,于是虚拟文件系统就与实际文件系统的操作衔接起来了。

 2.C标准库中的FILE结构和文件描述符

C语言中使用的是文件指针而不是文件描述符做为I/O的句柄."文件指针(file pointer)"指向进程用户区中的一个被称为FILE结构的数据结构。FILE结构包括一个缓冲区和一个文件描述符值.而文件描述符值是文件描述符表中的一个索引.从某种意义上说文件指针就是句柄的句柄。流(如: fopen)返回的是一个FILE结构指针, FILE结构是包含有文件描述符的,FILE结构函数可以看作是对fd直接操作的系统调用的封装, 它的优点是带有I/O缓存。

从文件描述符fd 到文件流 FILE* 的函数是
FILE* fdopen(int filedes,const char* mode);

早期的C标准库中,FILEstdio.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 }
Nach dem Login kopieren
Verwenden Sie im Programm

die Funktion fopen, um die Datei 2.txt zum Lesen und Schreiben zu öffnen nicht existiert, erstellen Sie dieses Dokument. Und es gibt den FILE-Zeiger myfile zurück. Verwenden Sie printf, um den Wert von myfile->_fileno an ein Standardterminal auszudrucken, und übergeben Sie myfile->_fileno als Dateideskriptor an write Systemaufruf zum Schreiben von Pufferdaten in die geöffnete Datei. Verwenden Sie dann den Befehl cat, um den Inhalt von 2.txt anzuzeigen. Das Ausführungsergebnis ist in der Abbildung dargestellt. Der Wert von _fileno ist 3, da die Standardeingabe, -ausgabe und -fehler 0, 1, 2 sind. Das Ausgabeergebnis lautet wie folgt: Daher ist das Mitglied
_fileno das Handle (Windows-System) oder der Dateideskriptor, der vom Betriebssystem beim Öffnen zurückgegeben wird die Datei. Für eingehendere Studien können Sie „CStandard Library“ lesen, herausgegeben vom People's Posts and Telecommunications Publishing House. Natürlich können Sie auch die Datei /glibc-2.9/manual/io.txti lesen. Linux, die Dateideskriptorzuweisung besteht darin, zu prüfen, ob der Dateideskriptor einzeln von klein nach groß verwendet wurde, und ihn dann zuzuweisen. Sie können auch ein Programm zum Testen schreiben.

Die Dateideskriptortabelle wird auch als Dateideskriptor-Array bezeichnet, in dem alle von einem Prozess geöffneten Dateien gespeichert werden. Das Dateideskriptor-Array ist in der vom Prozess geöffneten Dateitabellefiles_struct-Struktur enthalten. ist in /include/linux/fdtable.h definiert und ist ein Array von Zeigern, die auf den Datei-Typ ---fd_array[NR_OPEN_DEFAULT] verweisen, wobei NR_OPEN_DEFAULT auch in fdtable.h definiert ist. Dies ist eine Variable, die sich auf die spezifische CPU-Architektur bezieht, #define NR_OPEN_DEFAULTBITS_PER_LONG.

DATEI Struktur Die Beziehung zwischen dem Dateideskriptor und der Struktur der Datei kann durch die folgende Abbildung dargestellt werden:

Das obige ist der detaillierte Inhalt vonEinführung in das Konzept von Dateideskriptoren und FILE. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Empfehlungen
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!