共計(jì) 3398 個字符,預(yù)計(jì)需要花費(fèi) 9 分鐘才能閱讀完成。
本篇內(nèi)容主要講解“l(fā)inux fd 指的是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓丸趣 TV 小編來帶大家學(xué)習(xí)“l(fā)inux fd 指的是什么”吧!
在 linux 中,fd 全稱“File descriptor”,中文名為“文件描述符”,它是內(nèi)核為了高效管理這些已經(jīng)被打開的文件所創(chuàng)建的一種索引;它其實(shí)是一個非負(fù)整數(shù),用于指代被打開的文件,所有執(zhí)行 I / O 操作的系統(tǒng)調(diào)用都通過文件描述符來實(shí)現(xiàn)。
本教程操作環(huán)境:linux5.9.8 系統(tǒng)、Dell G3 電腦。
在 linux 中,fd 全稱“File descriptor”,中文名為“文件描述符”。文件描述符是一個非負(fù)整數(shù),本質(zhì)上是一個索引值(這句話非常重要)。
Linux 中的文件描述符(fd)
我們知道在 Linux 系統(tǒng)中一切皆可以看成是文件,文件又可分為:普通文件、目錄文件、鏈接文件和設(shè)備文件。在操作這些所謂的文件的時候,我們每操作一次就找一次名字,這會耗費(fèi)大量的時間和效率。所以 Linux 中規(guī)定每一個文件對應(yīng)一個索引,這樣要操作文件的時候,我們直接找到索引就可以對其進(jìn)行操作了。
文件描述符(file descriptor)就是內(nèi)核為了高效管理這些已經(jīng)被打開的文件所創(chuàng)建的索引,其是一個非負(fù)整數(shù)(通常是小整數(shù)),用于指代被打開的文件,所有執(zhí)行 I / O 操作的系統(tǒng)調(diào)用都通過文件描述符來實(shí)現(xiàn)。同時還規(guī)定系統(tǒng)剛剛啟動的時候,0 是標(biāo)準(zhǔn)輸入,1 是標(biāo)準(zhǔn)輸出,2 是標(biāo)準(zhǔn)錯誤。這意味著如果此時去打開一個新的文件,它的文件描述符會是 3,再打開一個文件文件描述符就是 4 ……
Linux 內(nèi)核對所有打開的文件有一個文件描述符表格,里面存儲了每個文件描述符作為索引與一個打開文件相對應(yīng)的關(guān)系,簡單理解就是下圖這樣一個數(shù)組,文件描述符(索引)就是文件描述符表這個數(shù)組的下標(biāo),數(shù)組的內(nèi)容就是指向一個個打開的文件的指針。
上面只是簡單理解,實(shí)際上關(guān)于文件描述符,Linux 內(nèi)核維護(hù)了 3 個數(shù)據(jù)結(jié)構(gòu):
進(jìn)程級的文件描述符表
系統(tǒng)級的打開文件描述符表
文件系統(tǒng)的 i -node 表
一個 Linux 進(jìn)程啟動后,會在內(nèi)核空間中創(chuàng)建一個 PCB 控制塊,PCB 內(nèi)部有一個文件描述符表(File descriptor table),記錄著當(dāng)前進(jìn)程所有可用的文件描述符,也即當(dāng)前進(jìn)程所有打開的文件。進(jìn)程級的描述符表的每一條記錄了單個進(jìn)程所使用的文件描述符的相關(guān)信息,進(jìn)程之間相互獨(dú)立,一個進(jìn)程使用了文件描述符 3,另一個進(jìn)程也可以用 3。除了進(jìn)程級的文件描述符表,系統(tǒng)還需要維護(hù)另外兩張表:打開文件表、i-node 表。這兩張表存儲了每個打開文件的打開文件句柄(open file handle)。一個打開文件句柄存儲了與一個打開文件相關(guān)的全部信息。
系統(tǒng)級的打開文件描述符表:
當(dāng)前文件偏移量(調(diào)用 read()和 write()時更新,或使用 lseek()直接修改)
打開文件時的標(biāo)識(open()的 flags 參數(shù))
文件訪問模式(如調(diào)用 open()時所設(shè)置的只讀模式、只寫模式或讀寫模式)
與信號驅(qū)動相關(guān)的設(shè)置
對該文件 i -node 對象的引用,即 i -node 表指針
文件系統(tǒng)的 i -node 表:
文件類型(例如:常規(guī)文件、套接字或 FIFO)和訪問權(quán)限
一個指針,指向該文件所持有的鎖列表
文件的各種屬性,包括文件大小以及與不同類型操作相關(guān)的時間戳
文件描述符、打開的文件句柄以及 i -node 之間的關(guān)系如下圖:
在進(jìn)程 A 中,文件描述符 1 和 20 都指向了同一個打開文件表項(xiàng),標(biāo)號為 23(指向了打開文件表中下標(biāo)為 23 的數(shù)組元素),這可能是通過調(diào)用 dup()、dup2()、fcntl() 或者對同一個文件多次調(diào)用了 open() 函數(shù)形成的。
進(jìn)程 A 的文件描述符 2 和進(jìn)程 B 的文件描述符 2 都指向了同一個文件,這可能是在調(diào)用 fork() 后出現(xiàn)的(即進(jìn)程 A、B 是父子進(jìn)程關(guān)系),或者是不同的進(jìn)程獨(dú)自去調(diào)用 open() 函數(shù)打開了同一個文件,此時進(jìn)程內(nèi)部的描述符正好分配到與其他進(jìn)程打開該文件的描述符一樣。
進(jìn)程 A 的描述符 0 和進(jìn)程 B 的描述符 3 分別指向不同的打開文件表項(xiàng),但這些表項(xiàng)均指向 i-node 表的同一個條目(標(biāo)號為 1976);換言之,它們指向了同一個文件。發(fā)生這種情況是因?yàn)槊總€進(jìn)程各自對同一個文件發(fā)起了 open() 調(diào)用。同一個進(jìn)程兩次打開同一個文件,也會發(fā)生類似情況。
這就說明:同一個進(jìn)程的不同文件描述符可以指向同一個文件;不同進(jìn)程可以擁有相同的文件描述符;不同進(jìn)程的同一個文件描述符可以指向不同的文件(一般也是這樣,除了 0、1、2 這三個特殊的文件);不同進(jìn)程的不同文件描述符也可以指向同一個文件。
Linux 上打開文件舉例
比如在 Linux 上用 vim test.py 打開一個文件,保持打開狀態(tài),再新打開一個新的 shell,輸入命令 pidof vim 獲取 vim 進(jìn)程的 pid 號,然后 ll /proc/$pid/fd 查看 vim 進(jìn)程所使用的文件描述符列表。
/dev/pts 是遠(yuǎn)程登陸 (telnet,ssh 等) 后創(chuàng)建的控制臺設(shè)備文件所在的目錄。因?yàn)槲沂峭ㄟ^ Xshell 遠(yuǎn)程登錄的,所以標(biāo)準(zhǔn)輸入 0,標(biāo)準(zhǔn)輸出 1,標(biāo)準(zhǔn)錯誤 2 的文件描述符都指向虛擬終端控制臺 /dev/pts/6。再看下面是新打開的 test.py 的文件描述符,竟然是 4,說好的從 3 開始呢?
這個我也困擾了好久,查了各種資料,終于在一個大佬的幫助下在一個論壇找到原因,有時候中文查不到還是要試試英文搜索啊。因?yàn)?vim 這種編輯器的原理是先打開源文件并拷貝,然后關(guān)閉源文件再打開自己的副本,修改完文件保存的時候直接將副本重命名覆蓋源文件。所以打開源文件的時候用的文件描述符 3,然后打開自己的副本是時候就該用文件描述符 4 了,然后關(guān)閉源文件,文件描述符 3 就被釋放了,我們查看的時候就只剩下了 4,這里它指向的是 vim 創(chuàng)建的副本文件。這里只是說個大概意思,具體深究要去深入了解一下 vim 的實(shí)現(xiàn)原理——奧爾特星云大使,下面是當(dāng)時我看到的論壇上的資料截圖,鏈接在這:StackOverFlow。
如果不相信可以試一試別的進(jìn)程,比如 tail。
在 Linux 上用 tail -f test.py 打開一個文件,保持打開狀態(tài),再新打開一個新的 shell,輸入命令 pidof tail 獲取 tail 進(jìn)程的 pid 號,然后 ll /proc/$pid/fd 查看 tail 進(jìn)程所使用的文件描述符列表,可以看到文件描述符確實(shí)是從 3 開始使用的。tail 不是編輯器不存在修改文件的情況,所以直接文件描述符直接打開的源文件。實(shí)際上可以使用 ll /proc/$pid/fd 命令獲取當(dāng)前運(yùn)行的任意進(jìn)程的文件描述符使用情況。
擴(kuò)展知識:Linux 配置系統(tǒng)最大打開文件描述符個數(shù)
(1)系統(tǒng)級限制
理論上系統(tǒng)內(nèi)存有多少就可以打開多少的文件描述符,但是在實(shí)際中內(nèi)核是會做相應(yīng)的處理,一般最大打開文件數(shù)會是系統(tǒng)內(nèi)存的 10%(以 KB 來計(jì)算),稱之為系統(tǒng)級限制。這個數(shù)字可以通過 cat /proc/sys/fs/file-max 或者 sysctl -a | grep fs.file-max 命令查看。
更改系統(tǒng)級限制有臨時更改和永久更改兩種方式:
臨時更改:session 斷開或者系統(tǒng)重啟后會恢復(fù)原來的設(shè)置值。使用命令 sysctl -w fs.file-max=xxxx,其中 xxxx 就是要設(shè)置的數(shù)字。
永久更改:vim 編輯 /etc/sysctl.conf 文件,在后面添加 fs.file-max=xxxx,其中 xxxx 就是要設(shè)置的數(shù)字。保存退出后還要使用 sysctl -p 命令使其生效。
(2)用戶級限制
同時為了控制每個進(jìn)程消耗的文件資源,內(nèi)核也會對單個進(jìn)程最大打開文件數(shù)做默認(rèn)限制,即用戶級限制。32 位系統(tǒng)默認(rèn)值一般是 1024,64 位系統(tǒng)默認(rèn)值一般是 65535,可以使用 ulimit -n 命令查看。
更改用戶級限制也有臨時更改和永久更改兩種方式:
臨時更改:session 斷開或者系統(tǒng)重啟后會恢復(fù)原來的設(shè)置值。使用命令 ulimit -SHn xxxx 命令來修改,其中 xxxx 就是要設(shè)置的數(shù)字。
永久更改:vim 編輯 /etc/security/limits.conf 文件,修改其中的 hard nofile xxxx 和 soft nofile xxxx,其中 xxxx 就是要設(shè)置的數(shù)字。保存后退出。
到此,相信大家對“l(fā)inux fd 指的是什么”有了更深的了解,不妨來實(shí)際操作一番吧!這里是丸趣 TV 網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!