1. 程式人生 > 其它 >Linux檔案描述符到底是什麼?

Linux檔案描述符到底是什麼?

一切皆檔案

Linux 中一切皆檔案,比如 C++ 原始檔、視訊檔案、Shell指令碼、可執行檔案等,就連鍵盤、顯示器、滑鼠等硬體裝置也都是檔案。一個 Linux 程序可以開啟成百上千個檔案,為了表示和區分已經開啟的檔案,Linux 會給每個檔案分配一個編號(一個 ID),這個編號就是一個整數,被稱為檔案描述符(File Descriptor)。
這只是一個形象的比喻,為了讓讀者容易理解我才這麼說。如果你也僅僅理解到這個層面,那不過是淺嘗輒止而已,並沒有看到檔案描述符的本質。
本篇文章的目的就是撥雲見霧,從底層實現的角度來給大家剖析一下檔案描述符,看看檔案描述如到底是如何表示一個檔案的。
不過,閱讀本篇文章需要你有C語言程式設計基礎,至少要理解陣列、指標和結構體;如果理解記憶體,那就更好了,看了這篇文章你會醍醐灌頂。
好了,廢話不多說,讓我們馬上進入正題吧。

Linux 檔案描述符到底是什麼?

一個 Linux 程序啟動後,會在核心空間中建立一個 PCB 控制塊,PCB 內部有一個檔案描述符表(File descriptor table),記錄著當前程序所有可用的檔案描述符,也即當前程序所有開啟的檔案。

核心空間是虛擬地址空間的一部分,想死磕的讀者請猛擊《C語言記憶體精講》,不想糾纏細節的讀者可以這樣理解:程序啟動後要佔用記憶體,其中一部分記憶體分配給了檔案描述符表。除了檔案描述符表,系統還需要維護另外兩張表:

  • 開啟檔案表(Open file table)
  • i-node 表(i-node table)

檔案描述符表每個程序都有一個,開啟檔案表和 i-node 表整個系統只有一個,它們三者之間的關係如下圖所示。

從本質上講,這三種表都是結構體陣列,0、1、2、73、1976 等都是陣列下標。表頭只是我自己新增的註釋,陣列本身是沒有的。實線箭頭表示指標的指向,虛線箭頭是我自己新增的註釋。

你看,檔案描述符只不過是一個數組下標嗎!

通過檔案描述符,可以找到檔案指標,從而進入開啟檔案表。該表儲存了以下資訊:

  • 檔案偏移量,也就是檔案內部指標偏移量。呼叫 read() 或者 write() 函式時,檔案偏移量會自動更新,當然也可以使用 lseek() 直接修改。
  • 狀態標誌,比如只讀模式、讀寫模式、追加模式、覆蓋模式等。
  • i-node 表指標。

然而,要想真正讀寫檔案,還得通過開啟檔案表的 i-node 指標進入 i-node 表,該表包含了諸如以下的資訊:

  • 檔案型別,例如常規檔案、套接字或 FIFO。
  • 檔案大小。
  • 時間戳,比如建立時間、更新時間。
  • 檔案鎖。

對上圖的進一步說明:

  • 在程序 A 中,檔案描述符 1 和 20 都指向了同一個開啟檔案表項,標號為 23(指向了開啟檔案表中下標為 23 的陣列元素),這可能是通過呼叫 dup()、dup2()、fcntl() 或者對同一個檔案多次呼叫了 open() 函式形成的。
  • 程序 A 的檔案描述符 2 和程序 B 的檔案描述符 2 都指向了同一個檔案,這可能是在呼叫 fork() 後出現的(即程序 A、B 是父子程序關係),或者是不同的程序獨自去呼叫 open() 函式打開了同一個檔案,此時程序內部的描述符正好分配到與其他程序開啟該檔案的描述符一樣。
  • 程序 A 的描述符 0 和程序 B 的描述符 3 分別指向不同的開啟檔案表項,但這些表項均指向 i-node 表的同一個條目(標號為 1976);換言之,它們指向了同一個檔案。發生這種情況是因為每個程序各自對同一個檔案發起了 open() 呼叫。同一個程序兩次開啟同一個檔案,也會發生類似情況。

有了以上對檔案描述符的認知,我們很容易理解以下情形:

  • 同一個程序的不同檔案描述符可以指向同一個檔案;
  • 不同程序可以擁有相同的檔案描述符;
  • 不同程序的同一個檔案描述符可以指向不同的檔案(一般也是這樣,除了 0、1、2 這三個特殊的檔案);
  • 不同程序的不同檔案描述符也可以指向同一個檔案。

轉自:https://blog.csdn.net/wan13141/article/details/89433379