Linux中的檔案描述符

2021-07-12 07:13:06 字數 3634 閱讀 2419

在linux系統中一切皆可以看成是檔案,檔案又可分為:普通檔案、目錄檔案、鏈結檔案和裝置檔案。檔案描述符(file descriptor)是核心為了高效管理已被開啟的檔案所建立的索引,其是乙個非負整數(通常是小整數),用於指代被開啟的檔案,所有執行i/o操作的系統呼叫都通過檔案描述符。程式剛剛啟動的時候,0是標準輸入,1是標準輸出,2是標準錯誤。如果此時去開啟乙個新的檔案,它的檔案描述符會是3。posix標準要求每次開啟檔案時(含socket)必須使用當前程序中

最小可用的檔案描述符號碼,因此,在網路通訊過程中稍不注意就有可能造成串話

。標準檔案描述符圖如下:

檔案描述與開啟的檔案對應模型如下圖:

在編寫檔案操作的或者網路通訊的軟體時,初學者一般可能會遇到「too many open files」的問題。這主要是因為檔案描述符是系統的乙個重要資源,雖然說系統記憶體有多少就可以開啟多少的檔案描述符,但是在實際實現過程中核心是會做相應的處理的,一般最大開啟檔案數會是系統記憶體的10%(以kb來計算)(稱之為系統級限制),檢視系統級別的最大開啟檔案數可以使用sysctl -a | grep fs.file-max命令檢視。與此同時,核心為了不讓某乙個程序消耗掉所有的檔案資源,其也會對單個程序最大開啟檔案數做預設值處理(稱之為使用者級限制),預設值一般是1024,使用ulimit -n命令可以檢視。在web伺服器中,通過更改系統預設值檔案描述符的最大值來優化伺服器是最常見的方式之一,具體優化方式請檢視

每乙個檔案描述符會與乙個開啟檔案相對應,同時,不同的檔案描述符也會指向同乙個檔案。相同的檔案可以被不同的程序開啟也可以在同乙個程序中被多次開啟。系統為每乙個程序維護了乙個檔案描述符表,該錶的值都是從0開始的,所以在不同的程序中你會看到相同的檔案描述符,這種情況下相同檔案描述符有可能指向同乙個檔案,也有可能指向不同的檔案。具體情況要具體分析,要理解具體其概況如何,需要檢視由核心維護的3個資料結構。

1. 程序級的檔案描述符表

2. 系統級的開啟檔案描述符表

3. 檔案系統的i-node表

程序級的描述符表的每一條目記錄了單個檔案描述符的相關資訊。

1. 控制檔案描述符操作的一組標誌。(目前,此類標誌僅定義了乙個,即close-on-exec標誌)

2. 對開啟檔案控制代碼的引用

核心對所有開啟的檔案的檔案維護有乙個系統級的描述符**(open file description table)。有時,也稱之為開啟檔案表(open file table),並將**中各條目稱為開啟檔案控制代碼(open file handle)。乙個開啟檔案控制代碼儲存了與乙個開啟檔案相關的全部資訊,如下所示:

1. 當前檔案偏移量(呼叫read()和write()時更新,或使用lseek()直接修改)

2. 開啟檔案時所使用的狀態標識(即,open()的flags引數)

3. 檔案訪問模式(如呼叫open()時所設定的唯讀模式、只寫模式或讀寫模式)

4. 與訊號驅動相關的設定

5. 對該檔案i-node物件的引用

6. 檔案型別(例如:常規檔案、套接字或fifo)和訪問許可權

7. 乙個指標,指向該檔案所持有的鎖列表

8. 檔案的各種屬性,包括檔案大小以及與不同型別操作相關的時間戳

下圖展示了檔案描述符、開啟的檔案控制代碼以及i-node之間的關係,圖中,兩個程序擁有諸多開啟的檔案描述符。

在程序a中,檔案描述符1和30都指向了同乙個開啟的檔案控制代碼(標號23)。這可能是通過呼叫dup()、dup2()、fcntl()或者對同乙個檔案多次呼叫了open()函式而形成的。

程序a的檔案描述符2和程序b的檔案描述符2都指向了同乙個開啟的檔案控制代碼(標號73)。這種情形可能是在呼叫fork()後出現的(即,程序a、b是父子程序關係),或者當某程序通過unix域套接字將乙個開啟的檔案描述符傳遞給另乙個程序時,也會發生。再者是不同的程序獨自去呼叫open函式開啟了同乙個檔案,此時程序內部的描述符正好分配到與其他程序開啟該檔案的描述符一樣。

此外,程序a的描述符0和程序b的描述符3分別指向不同的開啟檔案控制代碼,但這些控制代碼均指向i-node表的相同條目(1976),換言之,指向同乙個檔案。發生這種情況是因為每個程序各自對同乙個檔案發起了open()呼叫。同乙個程序兩次開啟同乙個檔案,也會發生類似情況。

1. 由於程序級檔案描述符表的存在,不同的程序中會出現相同的檔案描述符,它們可能指向同乙個檔案,也可能指向不同的檔案

2. 兩個不同的檔案描述符,若指向同乙個開啟檔案控制代碼,將共享同一檔案偏移量。因此,如果通過其中乙個檔案描述符來修改檔案偏移量(由呼叫read()、write()或lseek()所致),那麼從另乙個描述符中也會觀察到變化,無論這兩個檔案描述符是否屬於不同程序,還是同乙個程序,情況都是如此。

4. 檔案描述符標誌(即,close-on-exec)為程序和檔案描述符所私有。對這一標誌的修改將不會影響同一程序或不同程序中的其他檔案描述符

檔案描述符:

是個很小的正整數,它是乙個索引值,指向核心為每乙個程序所維護的該程序開啟檔案的記錄表。 

檔案描述符的優點:相容posix標準,許多linux和unix

系統呼叫都依賴於它。

檔案描述符的缺點:不能移植到unix以外的系統上去,也不直觀。

基於檔案描述符的輸入輸出函式

open:開啟乙個檔案,並指定訪問該檔案的方式,呼叫成功後返回乙個檔案描述符。

creat:開啟乙個檔案,如果該檔案不存在,則建立它,呼叫成功後返回乙個檔案描述符。

close:關閉檔案,程序對檔案所加的鎖全都被釋放。

read:從檔案描述符對應的檔案中讀取資料,呼叫成功後返回讀出的位元組數。

write:向檔案描述符對應的檔案中寫入資料,呼叫成功後返回寫入的位元組數。

ftruncate:把檔案描述符對應的檔案縮短到指定的長度,呼叫成功後返回0。

lseek:在檔案描述符對應的檔案裡把檔案指標設定到指定的位置,呼叫成功後返回新指標的位置。

fsync:將所有已寫入檔案中的資料真正寫到磁碟或其他下層裝置上,呼叫成功後返回0。

fchmod:把檔案描述符對應的檔案的許可權位改為指定的八進位制模式,呼叫成功後返回0。

flock:用於向檔案描述符對應的檔案施加建議性鎖,呼叫成功後返回0。

fcntl:既能施加建議性鎖也能施加強制性鎖,能建立記錄鎖、讀取鎖和寫入鎖,呼叫成功後返回0。

dup:複製檔案描述符,返回沒使用的檔案描述符中最小的編號。

dup2:由使用者指定返回的檔案描述符的值,用來重新開啟或重定向乙個檔案描述符。

select:同時從多個檔案描述符讀取資料或向多個檔案描述符寫入資料

linux檔案描述符

本文介紹了檔案描述符,1 首先說什麼是檔案描述符,它有什麼作用?檔案描述符是乙個簡單的整數,用以標明每乙個被程序所開啟的檔案和socket。基於檔案描述符的輸入輸出函式 open 開啟乙個檔案,並指定訪問該檔案的方式,呼叫成功後返回乙個檔案描述符。creat 開啟乙個檔案,如果該檔案不存在,則建立它...

linux檔案描述符

當某個程式開啟檔案時,作業系統返回相應的檔案描述符,程式為了處理該檔案必須引用此描述符。所謂的檔案描述符是乙個低階的正整數。最前面的三個檔案描述符 0,1,2 分別與標準輸入 stdin 標準輸出 stdout 和標準錯誤 stderr 對應。因此,函式 scanf 使用 stdin,而函式 pri...

Linux 檔案描述符

我們之前就知道在linux作業系統下 一切皆檔案 所以在這個條件下,所有研究的物件都變相的相當於研究檔案,那麼對檔案系統的研究也應該是必須的。我們的核心利用檔案描述符來訪問檔案,每個檔案描述符都是非負整數,開啟現存的檔案或者是新建檔案時,核心會返回乙個檔案描述符,讀寫檔案也需要使用檔案描述符來指定待...