一些概念:
1.為了便于統(tǒng)一管理寻狂,系統(tǒng)將所有的輸入/輸出設(shè)備都視為文件瞬项,按文件方式提供給用戶使用蔗蹋,如目錄的檢索、權(quán)限的驗(yàn)證等都與普通文件相似囱淋,只是對(duì)這些文件的操作是和設(shè)備驅(qū)動(dòng)程序緊密相連的猪杭,系統(tǒng)將這些操作轉(zhuǎn)為對(duì)具體設(shè)備的操作。
2.當(dāng)用戶第一次請(qǐng)求對(duì)某文件進(jìn)行操作時(shí)妥衣,先利用 open 系統(tǒng)調(diào)用將該文件打開(kāi)胁孙。所謂“打開(kāi)”,是指系統(tǒng)將指名文件的屬性(包括該文件在外存上的物理位置)從外存拷貝到內(nèi)存打開(kāi)文件表的一個(gè)表目中称鳞,并將該表目的編號(hào)(或稱為索引)返回給用戶。以后稠鼻,當(dāng)用戶再要求對(duì)該文件進(jìn)行相應(yīng)的操作時(shí)冈止,便可利用系統(tǒng)所返回的索引號(hào)向系統(tǒng)提出操作請(qǐng)求。系統(tǒng)這時(shí)便可直接利用該索引號(hào)到打開(kāi)文件表中去查找候齿,從而避免了對(duì)該文件的再次檢索熙暴。這樣不僅節(jié)省了大量的檢索開(kāi)銷,也顯著地提高了對(duì)文件的操作速度慌盯。如果用戶已不再需要對(duì)該文件實(shí)施相應(yīng)的操作時(shí)周霉,可利用“關(guān)閉”(close)系統(tǒng)調(diào)用來(lái)關(guān)閉此文件,OS將會(huì)把該文件從打開(kāi)文件表中的表目上刪除掉
3.POSIX標(biāo)準(zhǔn)(標(biāo)準(zhǔn)應(yīng)用程序接口(API)定義的一組系統(tǒng)調(diào)用的功能亚皂,其實(shí)是一組過(guò)程俱箱,真正的系統(tǒng)調(diào)用是中斷命令,然后根據(jù)信號(hào)進(jìn)入相應(yīng)的中斷程序灭必。open就是一個(gè)POSIX API接口狞谱,POSIX是為了可以讓程序兼容多種操作系統(tǒng)的乃摹。
node創(chuàng)建了子進(jìn)程前,先創(chuàng)建IPC通道跟衅,為了便于統(tǒng)一管理孵睬,系統(tǒng)將所有的輸入/輸出設(shè)備都視為文件,按文件方式提供給用戶使用伶跷。創(chuàng)建了IPC返回對(duì)應(yīng)的文件描述符掰读,文件描述符其實(shí)相當(dāng)于一個(gè)表目的索引,保存在內(nèi)存中叭莫。創(chuàng)建了子進(jìn)程之后蹈集,子進(jìn)程通過(guò)環(huán)境變量NODE_CHANNEL_FD告訴子進(jìn)程這個(gè)IPC文件的描述符,子進(jìn)程在啟動(dòng)的過(guò)程中根據(jù)文件描述符連接IPC通道食寡,從而完成了父子進(jìn)程之間的連接雾狈。這個(gè)IPC和網(wǎng)絡(luò)socket相類似(創(chuàng)建一個(gè)socket也需要一個(gè)文件描述符)。
以上是個(gè)人理解
ps:句柄其實(shí)和描述符一樣抵皱,其實(shí)都是指向指針的指針善榛。
轉(zhuǎn)載請(qǐng)說(shuō)明出處:http://blog.csdn.net/cywosp/article/details/38965239
1. 概述
在Linux系統(tǒng)中一切皆可以看成是文件,文件又可分為:普通文件呻畸、目錄文件移盆、鏈接文件和設(shè)備文件。文件描述符(file descriptor)是內(nèi)核為了高效管理已被打開(kāi)的文件所創(chuàng)建的索引伤为,其是一個(gè)非負(fù)整數(shù)(通常是小整數(shù))咒循,用于指代被打開(kāi)的文件,所有執(zhí)行I/O操作的系統(tǒng)調(diào)用都通過(guò)文件描述符绞愚。程序剛剛啟動(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)碼,因此,在網(wǎng)絡(luò)通信過(guò)程中稍不注意就有可能造成串話。標(biāo)準(zhǔn)文件描述符圖如下:
文件描述與打開(kāi)的文件對(duì)應(yīng)模型如下圖:
2. 文件描述限制
在編寫文件操作的或者網(wǎng)絡(luò)通信的軟件時(shí),初學(xué)者一般可能會(huì)遇到“Too many open files”的問(wèn)題辙谜。這主要是因?yàn)槲募枋龇窍到y(tǒng)的一個(gè)重要資源,雖然說(shuō)系統(tǒng)內(nèi)存有多少就可以打開(kāi)多少的文件描述符感昼,但是在實(shí)際實(shí)現(xiàn)過(guò)程中內(nèi)核是會(huì)做相應(yīng)的處理的装哆,一般最大打開(kāi)文件數(shù)會(huì)是系統(tǒng)內(nèi)存的10%(以KB來(lái)計(jì)算)(稱之為系統(tǒng)級(jí)限制),查看系統(tǒng)級(jí)別的最大打開(kāi)文件數(shù)可以使用sysctl -a | grep fs.file-max命令查看。與此同時(shí)烂琴,內(nèi)核為了不讓某一個(gè)進(jìn)程消耗掉所有的文件資源爹殊,其也會(huì)對(duì)單個(gè)進(jìn)程最大打開(kāi)文件數(shù)做默認(rèn)值處理(稱之為用戶級(jí)限制),默認(rèn)值一般是1024奸绷,使用ulimit -n命令可以查看梗夸。在Web服務(wù)器中,通過(guò)更改系統(tǒng)默認(rèn)值文件描述符的最大值來(lái)優(yōu)化服務(wù)器是最常見(jiàn)的方式之一号醉,具體優(yōu)化方式請(qǐng)查看http://blog.csdn.net/kumu_linux/article/details/7877770反症。
3. 文件描述符合打開(kāi)文件之間的關(guān)系
每一個(gè)文件描述符會(huì)與一個(gè)打開(kāi)文件相對(duì)應(yīng),同時(shí)畔派,不同的文件描述符也會(huì)指向同一個(gè)文件铅碍。相同的文件可以被不同的進(jìn)程打開(kāi)也可以在同一個(gè)進(jìn)程中被多次打開(kāi)。系統(tǒng)為每一個(gè)進(jìn)程維護(hù)了一個(gè)文件描述符表线椰,該表的值都是從0開(kāi)始的胞谈,所以在不同的進(jìn)程中你會(huì)看到相同的文件描述符,這種情況下相同文件描述符有可能指向同一個(gè)文件憨愉,也有可能指向不同的文件烦绳。具體情況要具體分析,要理解具體其概況如何配紫,需要查看由內(nèi)核維護(hù)的3個(gè)數(shù)據(jù)結(jié)構(gòu)径密。
1. 進(jìn)程級(jí)的文件描述符表
2. 系統(tǒng)級(jí)的打開(kāi)文件描述符表
3. 文件系統(tǒng)的i-node表
進(jìn)程級(jí)的描述符表的每一條目記錄了單個(gè)文件描述符的相關(guān)信息。
1. 控制文件描述符操作的一組標(biāo)志躺孝。(目前享扔,此類標(biāo)志僅定義了一個(gè),即close-on-exec標(biāo)志)
2. 對(duì)打開(kāi)文件句柄的引用
內(nèi)核對(duì)所有打開(kāi)的文件的文件維護(hù)有一個(gè)系統(tǒng)級(jí)的描述符表格(open file description table)植袍。有時(shí)惧眠,也稱之為打開(kāi)文件表(open file table),并將表格中各條目稱為打開(kāi)文件句柄(open file handle)于个。一個(gè)打開(kāi)文件句柄存儲(chǔ)了與一個(gè)打開(kāi)文件相關(guān)的全部信息锉试,如下所示:
1. 當(dāng)前文件偏移量(調(diào)用read()和write()時(shí)更新,或使用lseek()直接修改)
2. 打開(kāi)文件時(shí)所使用的狀態(tài)標(biāo)識(shí)(即览濒,open()的flags參數(shù))
3. 文件訪問(wèn)模式(如調(diào)用open()時(shí)所設(shè)置的只讀模式、只寫模式或讀寫模式)
4. 與信號(hào)驅(qū)動(dòng)相關(guān)的設(shè)置
5. 對(duì)該文件i-node對(duì)象的引用
6. 文件類型(例如:常規(guī)文件拖云、套接字或FIFO)和訪問(wèn)權(quán)限
7. 一個(gè)指針贷笛,指向該文件所持有的鎖列表
8. 文件的各種屬性,包括文件大小以及與不同類型操作相關(guān)的時(shí)間戳
下圖展示了文件描述符宙项、打開(kāi)的文件句柄以及i-node之間的關(guān)系乏苦,圖中,兩個(gè)進(jìn)程擁有諸多打開(kāi)的文件描述符。
在進(jìn)程A中汇荐,文件描述符1和30都指向了同一個(gè)打開(kāi)的文件句柄(標(biāo)號(hào)23)洞就。這可能是通過(guò)調(diào)用dup()、dup2()掀淘、fcntl()或者對(duì)同一個(gè)文件多次調(diào)用了open()函數(shù)而形成的旬蟋。
進(jìn)程A的文件描述符2和進(jìn)程B的文件描述符2都指向了同一個(gè)打開(kāi)的文件句柄(標(biāo)號(hào)73)。這種情形可能是在調(diào)用fork()后出現(xiàn)的(即革娄,進(jìn)程A倾贰、B是父子進(jìn)程關(guān)系),或者當(dāng)某進(jìn)程通過(guò)UNIX域套接字將一個(gè)打開(kāi)的文件描述符傳遞給另一個(gè)進(jìn)程時(shí)拦惋,也會(huì)發(fā)生匆浙。再者是不同的進(jìn)程獨(dú)自去調(diào)用open函數(shù)打開(kāi)了同一個(gè)文件,此時(shí)進(jìn)程內(nèi)部的描述符正好分配到與其他進(jìn)程打開(kāi)該文件的描述符一樣厕妖。
此外首尼,進(jìn)程A的描述符0和進(jìn)程B的描述符3分別指向不同的打開(kāi)文件句柄,但這些句柄均指向i-node表的相同條目(1976)言秸,換言之软能,指向同一個(gè)文件。發(fā)生這種情況是因?yàn)槊總€(gè)進(jìn)程各自對(duì)同一個(gè)文件發(fā)起了open()調(diào)用井仰。同一個(gè)進(jìn)程兩次打開(kāi)同一個(gè)文件埋嵌,也會(huì)發(fā)生類似情況。
4. 總結(jié)
1. 由于進(jìn)程級(jí)文件描述符表的存在俱恶,不同的進(jìn)程中會(huì)出現(xiàn)相同的文件描述符雹嗦,它們可能指向同一個(gè)文件,也可能指向不同的文件
2. 兩個(gè)不同的文件描述符合是,若指向同一個(gè)打開(kāi)文件句柄了罪,將共享同一文件偏移量。因此聪全,如果通過(guò)其中一個(gè)文件描述符來(lái)修改文件偏移量(由調(diào)用read()泊藕、write()或lseek()所致),那么從另一個(gè)描述符中也會(huì)觀察到變化难礼,無(wú)論這兩個(gè)文件描述符是否屬于不同進(jìn)程娃圆,還是同一個(gè)進(jìn)程,情況都是如此蛾茉。
3. 要獲取和修改打開(kāi)的文件標(biāo)志(例如:O_APPEND讼呢、O_NONBLOCK和O_ASYNC),可執(zhí)行fcntl()的F_GETFL和F_SETFL操作谦炬,其對(duì)作用域的約束與上一條頗為類似悦屏。
4. 文件描述符標(biāo)志(即节沦,close-on-exec)為進(jìn)程和文件描述符所私有。對(duì)這一標(biāo)志的修改將不會(huì)影響同一進(jìn)程或不同進(jìn)程中的其他文件描述符