理解文件描述符


前言

何為文件?

Linux 下,一切皆文件

在Linux操作系統(tǒng)中,可以將一切都看作是文件,包括普通文件,目錄文件,字符設(shè)備文件(如鍵盤(pán),鼠標(biāo)...),塊設(shè)備文件(如硬盤(pán),光驅(qū)...),套接字等等,所有一切均抽象成文件,提供了統(tǒng)一的接口,方便應(yīng)用程序調(diào)用

文件描述符

既然在Linux操作系統(tǒng)中,你將一切都抽象為了文件,那么對(duì)于一個(gè)打開(kāi)的文件,我應(yīng)用程序怎么對(duì)應(yīng)上呢?

文件描述符應(yīng)運(yùn)而生

文件描述符:簡(jiǎn)稱(chēng)fd,當(dāng)應(yīng)用程序請(qǐng)求內(nèi)核打開(kāi)/新建一個(gè)文件時(shí),內(nèi)核會(huì)返回一個(gè)文件描述符用于對(duì)應(yīng)這個(gè)打開(kāi)/新建的文件,其fd本質(zhì)上就是一個(gè)非負(fù)整數(shù),讀寫(xiě)文件也是需要使用這個(gè)文件描述符來(lái)指定待讀寫(xiě)的文件的

內(nèi)核

操作系統(tǒng)的核心叫內(nèi)核,是一個(gè)獨(dú)立的軟件

操作系統(tǒng)為每一個(gè)進(jìn)程維護(hù)了一個(gè)文件描述符表,該表的索引值都從從0開(kāi)始的,所以在不同的進(jìn)程中可以看到相同的文件描述符,這種情況下相同的文件描述符可能指向同一個(gè)文件,也可能指向不同的文件,具體情況需要具體分析,下面用一張簡(jiǎn)圖就可以很容易的明白了

摘自https://www.cnblogs.com/DengGao/p/file_symbol.html

通過(guò)上圖可以看到,當(dāng)不同進(jìn)程中出現(xiàn)相同的文件描述符時(shí),可能實(shí)際對(duì)應(yīng)的文件并不是同一個(gè),相反不同進(jìn)程中不同的文件描述符也可可能對(duì)應(yīng)同一個(gè)文件

當(dāng)一個(gè)應(yīng)用程序剛剛啟動(dòng)的時(shí)候,0是標(biāo)準(zhǔn)輸入,1是標(biāo)準(zhǔn)輸出,2是標(biāo)準(zhǔn)錯(cuò)誤。如果此時(shí)去打開(kāi)一個(gè)新的文件,它的文件描述符會(huì)是3。POSIX標(biāo)準(zhǔn)要求每次打開(kāi)文件時(shí)(含socket)必須使用當(dāng)前進(jìn)程中最小可用的文件描述符號(hào)

文件描述符限制

文件描述符是一個(gè)重要的系統(tǒng)資源,理論上系統(tǒng)內(nèi)存多大就應(yīng)該可以打開(kāi)多少個(gè)文件描述符,但是實(shí)際情況是,內(nèi)核會(huì)有系統(tǒng)級(jí)限制,以及用戶級(jí)限制(不讓某一個(gè)應(yīng)用程序進(jìn)程消耗掉所有的文件資源,可以使用ulimit -n 查看)

文件描述符唯一性

進(jìn)程 + 文件描述符ID確認(rèn),因?yàn)閮?nèi)核為每個(gè)進(jìn)程都有一份其所屬的文件描述符表

對(duì)應(yīng)關(guān)系

應(yīng)用程序進(jìn)程拿到的文件描述符ID == 進(jìn)程文件描述符表的索引,通過(guò)索引拿到文件指針,指向系統(tǒng)級(jí)文件描述符表的文件偏移量,再通過(guò)文件偏移量找到inode指針,最終對(duì)應(yīng)到真實(shí)的文件

Socket

最后說(shuō)下套接字,套接字也是文件,當(dāng)server端監(jiān)聽(tīng)到有連接時(shí),應(yīng)用程序會(huì)請(qǐng)求內(nèi)核創(chuàng)建Socket,Socket創(chuàng)建好后會(huì)返回一個(gè)文件描述符給應(yīng)用程序,當(dāng)有數(shù)據(jù)包過(guò)來(lái)網(wǎng)卡時(shí),內(nèi)核會(huì)通過(guò)數(shù)據(jù)包的源端口,源ip,目的端口等在內(nèi)核維護(hù)的一個(gè)ipcb雙向鏈表中找到對(duì)應(yīng)的Socket,并將數(shù)據(jù)包賦值到該Socket的緩沖區(qū),應(yīng)用程序請(qǐng)求讀取Socket中的數(shù)據(jù)時(shí),內(nèi)核就會(huì)將數(shù)據(jù)拷貝到應(yīng)用程序的內(nèi)存空間,從而完成讀取Socket數(shù)據(jù)

這里提一下,操作系統(tǒng)針對(duì)不同的傳輸方式(TCP,UDP)會(huì)在內(nèi)核中各自維護(hù)一個(gè)Socket雙向鏈表,當(dāng)數(shù)據(jù)包到達(dá)網(wǎng)卡時(shí),會(huì)根據(jù)數(shù)據(jù)包的源端口,源ip,目的端口從對(duì)應(yīng)的鏈表中找到其對(duì)應(yīng)的Socket,并會(huì)將數(shù)據(jù)拷貝到Socket的緩沖區(qū),等待應(yīng)用程序讀取

最后附上Linux中進(jìn)程結(jié)構(gòu)圖

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容