[linux]文件描述符再探

第一點也是最重要的一點:在linux上所有的硬件掛載/dev/mouse,pipe,文件,socket等都是文件!都是可以通過文件描述符來訪問到的。


文件描述符file descriptor:是一個對文件的索引號,可以認爲是一個公司裏面的員工id號,通過id可以索引到員工,然後對員工進行一些操作。

首先要理解文件描述符,得有如下3個內核所維護的數據結構概念:

1.進程級的文件描述符

2.系統級的打開文件表

3.文件系統的i-node表


進程級的文件描述符:

針對於每一個進程,內核都會維護打開文件的描述符表,表中的每一條記錄都記錄了單個文件的相關信息,控制文件描述操作的標誌,對打開句柄的引用,這裏的句柄是指系統級打開文件表中的條目。


系統級的打開文件表

內核對所有打開的文件維護一個系統級的文件打開表,並將表中的各條目稱之爲打開句柄。一個句柄存儲了打開文件的相關信息。包括文件偏移,打開文件狀態flags,文件的訪問模式,信號驅動I/O相關設置,對文件系統中的i-node的引用。


文件系統的i-node表:

目前linux的文件系統已經到了ext4,想知道自己系統的文件系統是什麼 可以使用

df -aT
進行查看。一個文件在linux中可以有屬性,權限,數據信息。ext文件系統通暢將這兩部分的數據分別存放在不同的快,權限和屬性放在inode中,實際數據則放在data block中。

一個文件會佔用一個inode,inode記錄文件的數據所在的block號碼。如下圖所示:


假設一個文件存放在inode4號,而這個文件實際放在了2,7,13,15這四個data block中,此時操作系統讀出四個block就能將文件內容讀出。




在程序中一個默認使用了3個文件描述符 0 ~ 2, 標準輸入輸出錯誤:STDIN_FILENO = 0,STDOUT_FILENO = 1,STDERR_FILENO = 2。

當用

int open(char* name,int flags,.../* mode_t mode */);
當開一個文件的時候,會返回最低的未使用的文件描述符序號,當標準輸入,輸出,錯誤被佔用的情況下,將返回3;


上圖中進程A的文件描述符fd 1 和 20是指向同一個句柄,這可能是因爲使用了dup(),dup2(),fcntl()函數產生的

進程A的文件描述符 fd 2和 進程B的文件描述符 fd 2都指向同一個句柄,這可能是因爲執行fork()之後,產生的內存拷貝,即A和B是父子進程關係,繼承來的。

進程A的文件描述符 fd 0 和 進程B的文件描述符 fd 3 指向不同的句柄,但是指向同一個inode,可能是因爲都打開了同一個文件,同一個進程兩次打開一個文件也會發生這種情況。


總結:兩個不同的文件描述符,若指向同一個打開文件句柄,則共享偏移,即通過一個文件描述符更改內容,另外一個文件描述符也是可以觀察到的。


那麼兩條命令行

./run_script >result.log 2>result.log

./run_script >result.log 2>&1

第一條命令行 相當於 創建了兩個文件描述符,但是不共享句柄,即偏移不共享,這就會產生十分怪異的情況,即輸出結果是亂序的

第二條命兩行 將文件描述符複製標準輸入文件描述符,共享句柄,共享偏移,輸出結果和控制檯輸出結果是一致的。

複製描述符 可以用

int dup(int oldfd);
int dup2(int oldfd,int newfd);

dup()函數會複製一個文件描述符,返回一個指向相同句柄的新文件描述符,新文件描述符從最低未使用的描述符選擇。

比如:

close(STDIN_FILENO);
newfd = dup(STDOUT_FILENO);
這個時候 newfd就是0。因爲標準輸入所佔用的文件描述符爲0,這個時候關閉了,0變成未使用,那麼dup之後將使得newfd將變成0即最小未使用的文件描述符。

dup2()所執行的功能即 若是指定的新的文件描述符存在,則關閉,然後返回,否則直接返回。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章