首頁 >運維 >linux運維 >linux fd是什麼

linux fd是什麼

青灯夜游
青灯夜游原創
2022-05-09 16:24:349441瀏覽

在linux中,fd全名為“File descriptor”,中文名為“文件描述符”,它是內核為了高效管理這些已經被打開的文件所創建的一種索引;它其實是一個非負整數,用來指稱被開啟的文件,所有執行I/O操作的系統呼叫都透過文件描述符來實現。

linux fd是什麼

本教學操作環境:linux7.3系統、Dell G3電腦。

在linux中,fd全名為“File descriptor”,中文名稱為“檔案描述子”。文件描述符是一個非負整數,本質上是索引值(這句話非常重要)。

Linux中的文件描述符(fd)

我們知道在Linux系統中一切皆可以看成是文件,文件又可分為:普通文件、目錄檔案、連結檔案和設備檔案。在操作這些所謂的文件的時候,我們每操作一次就找一次名字,這會耗費大量的時間和效率。所以Linux中規定每一個檔案對應一個索引,這樣要操作檔案的時候,我們直接找到索引就可以對其進行操作了。

檔案描述子(file descriptor)就是核心為了有效率地管理這些已經被開啟的檔案所建立的索引,其是一個非負整數(通常是小整數),用來指涉被開啟的文件,所有執行I/O操作的系統呼叫都透過檔案描述符來實現。同時也規定係統剛啟動的時候,0是標準輸入,1是標準輸出,2是標準錯誤。這意味著如果此時去打開一個新的文件,它的文件描述符會是3,再打開一個文件文件描述符就是4......

Linux內核對所有打開的文件有一個文件描述符表格,裡面儲存了每個文件描述符作為索引與一個打開文件相對應的關係,簡單理解就是下圖這樣一個數組,文件描述符(索引)就是文件描述符表這個數組的下標,數組的內容就是指向一個個打開的檔案的指標。

linux fd是什麼

上面只是簡單理解,實際上關於檔案描述符,Linux核心維護了3個資料結構

  • 進程級的檔案描述子表
  • 系統層級的開啟檔案描述子表
  • 檔案系統的i-node表

一個Linux 行程啟動後,會在核心空間中建立一個PCB 控制區塊,PCB 內部有一個檔案描述符表(File descriptor table),記錄著目前行程所有可用的檔案描述符,也也就是目前行程所有開啟的檔案。進程層級的描述符表的每一筆記錄了單一進程所使用的檔案描述符的相關訊息,進程之間相互獨立,一個進程使用了檔案描述符3,另一個進程也可以用3。除了進程層級的檔案描述子表,系統還需要維護另外兩張表:開啟檔案表、i-node 表。這兩張表儲存了每個開啟檔案的開啟檔案句柄(open file handle)。一個開啟檔案句柄儲存了與一個開啟檔案相關的全部資訊。

系統層級的開啟檔案描述表:

  • 目前檔案偏移量(當呼叫read()和write()時更新,或使用lseek ()直接修改)
  • 開啟檔案時的標識(open()的flags參數)
  • #檔案存取模式(如呼叫open()時所設定的唯讀模式、只寫模式或讀寫模式)
  • 與訊號驅動程式相關的設定
  • 對該檔案i-node物件的引用,即i-node 表指標

檔案系統的i-node表:

  • 檔案類型(例如:常規檔案、套接字或FIFO)和存取權限
  • 一個指針,指向該文件所持有的鎖定清單
  • 檔案的各種屬性,包括檔案大小以及與不同類型操作相關的時間戳記

檔案描述子、開啟的檔案句柄以及i-node之間的關係如下圖:

linux fd是什麼

  • 在進程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 這三個特殊的檔案);不同流程的不同檔案描述子也可以指向同一個檔案。

Linux上開啟檔案範例

例如在Linux上用 vim test.py #」開啟一個文件,保持開啟狀態,再新開啟一個新的shell,輸入指令pidof vim 取得vim行程的pid號,然後 ll  /proc/$pid/fd 檢視vim 行程所使用的文件描述符列表。

/dev/pts是遠端登陸(telnet,ssh等)後建立的控制台裝置檔案所在的目錄。因為我是透過Xshell遠端登入的,所以標準輸入0,標準輸出1,標準錯誤2的檔案描述子都指向虛擬終端控制台 /dev/pts/6 。 再看下面是新開啟的 test.py 的檔案描述符,竟然是4,說好的從3開始呢?

這個我也困擾了好久,查了各種資料,終於在一個大佬的幫助下在一個論壇找到原因,有時候中文查不到還是要試試英文搜尋啊。因為vim這種編輯器的原理是先開啟來源檔案並拷貝,然後關閉來源檔案再開啟自己的副本,修改完檔案儲存的時候直接將副本重新命名覆蓋來源檔案。所以打開原始檔的時候用的文件描述符3,然後打開自己的副本是時候就該用文件描述符4了,然後關閉源文件,文件描述符3就被釋放了,我們查看的時候就只剩下了4,這裡它指向的是vim創建的副本檔案。這裡只是說個大概意思,具體深究要去深入了解一下 vim的實現原理——奧爾特星雲大使,下面是當時我看到的論壇上的資料截圖,鏈接在這:StackOverFlow。

linux fd是什麼

如果不相信可以試試看別的進程,例如 tail。

在Linux上用 tail -f test.py 開啟一個文件,保持開啟狀態,再新開啟新的shell,輸入指令pidof tail 取得tail進程的pid號,然後 ll  /proc/$pid/fd 查看tail進程所使用的檔案描述子列表,可以看到檔案描述子確實是從3開始使用的。 tail不是編輯器不存在修改文件的情況,所以直接文件描述符直接打開的來源文件。實際上可以使用 ll  /proc/$pid/fd 指令來取得目前執行的任一進程的檔案描述符使用情況。

擴充知識:Linux設定係統最大開啟檔案描述子數

( 1)系統級限制

理論上系統記憶體有多少就可以開啟多少的檔案描述符,但是在實際中核心是會做對應的處理,一般最大開啟檔案數會是系統記憶體的10%(以KB來計算),稱之為系統級限制。這個數字可以透過 cat /proc/sys/fs/file-max 或 sysctl -a | grep fs.file-max 指令查看。

更改系統級限制有暫時更改和永久更改兩種方式:

  • 暫時更改:session斷開或系統重啟後會恢復原來的設定值。使用指令 sysctl -w fs.file-max=xxxx,其中xxxx就是要設定的數字。

  • 永久更改:vim編輯 /etc/sysctl.conf 文件,在後面加上 fs.file-max=xxxx,其中xxxx就是要設定的數字。儲存退出後也要使用sysctl -p 指令使其生效。

(2)用戶級限制

同時為了控制每個行程消耗的檔案資源,核心也會對單一行程最大開啟文件數做預設限制,即用戶級限制。 32位元系統預設值一般是1024,64位元系統預設值一般是65535,可以使用 ulimit -n 指令查看。

更改用戶級限制也有暫時更改和永久更改兩種方式:

  • 暫時更改:session斷開或系統重啟後會恢復原來的設定值。使用指令 ulimit -SHn xxxx 指令來修改,其中xxxx就是要設定的數字。

  • 永久更改:vim編輯 /etc/security/limits.conf 文件,修改其中的hard nofile xxxxsoft nofile xxxx,其中xxxx就是要設定的數字。儲存後退出。關於hard和soft的區別,請參考下面參考連結中的第5個。

相關推薦:《Linux影片教學

以上是linux fd是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn