在 Unix 和類 Unix 操作系統中,檔案描述符(FD)是每個進程的唯一識別碼,用於識別檔案或其他輸入/輸出資源,如管道或網路套接字。這些描述符通常使用非負整數值,大多數情況下,負值則表示「無值」或錯誤條件。檔案描述符是 POSIX API 的一部分,所有 Unix 進程通常都需要三個標準的 POSIX 檔案描述符,這些描述符對應於三個標準流:標準輸入(stdin)、標準輸出(stdout)和標準錯誤(stderr)。
每個 Unix 進程的檔案描述符都對應一個由內核維護的進程檔案描述符表,這表格又索引到所有進程共用的一個系統級文件表,該表記錄了檔案被打開的模式,例如:讀取、寫入及附加等模式。
檔案描述符的使用是執行輸入和輸出的基礎。當進程需要進行這些操作時,它會透過系統調用將檔案描述符傳遞給內核,內核則代表進程訪問檔案。進程無法直接訪問檔案或索引表。對於 Linux 系統,進程中打開的檔案描述符可以在路徑 /proc/PID/fd/
下找到,這裡的 PID
是進程識別碼。
例如,檔案描述符 /proc/PID/fd/0
對應標準輸入,/proc/PID/fd/1
是標準輸出,而 /proc/PID/fd/2
則是標準錯誤。任何正在運行的進程也可以透過 /proc/self/fd
和 /dev/fd
這兩個資料夾來訪問自身的檔案描述符。
在現代類 Unix 系統上,檔案描述符的操作非常多樣。通常這些操作包含創建檔案描述符、衍生檔案描述符,以及針對單一或多個檔案描述符進行的操作等。以下是一些基本的檔案描述符操作:
創建檔案描述符的典型方法包括:
open()
creat()
socket()
pipe()
可以通過以下方法衍生檔案描述符:
dirfd()
fileno()
對檔案描述符進行操作例如:
read()
write()
lseek()
處理多個檔案描述符的操作包括:
select()
poll()
這些操作不僅使得檔案描述符成為優雅的功能接口,也簡化了進程間的通信。
Unix 檔案描述符在許多方面表現得像是能力(capabilities)。它們可以透過 Unix 域套接字在進程間傳遞,這使得資源的共享變得靈活。但要注意的是,這會導致可變狀態的問題,因為多個進程之間共享同一個打開檔案的描述符時,可能會互相干擾。
隨著 Unix 和類 Unix 系統的演進,許多新的操作和庫已被增添,這些操作的目的是防止某類特定的 TOCTOU 攻擊。這些操作包括 openat()
和其他相關操作。
了解檔案描述符的運作原理不僅對程式員來說至關重要,對於每一個使用類 Unix 系統的人來說都十分必要。它們是進程間交流的關鍵橋樑,為整個系統的運行提供了基礎架構。隨著科技的快速發展,這個曾被認為基礎的概念或許會引發新的思考與挑戰。在這樣的情況下,我們不禁要問,未來的檔案描述符將朝著何處演進,並如何影響我們的計算和溝通方式?