什麼是句柄和文件描述符

什麼是句柄

  1. 句柄就是一個標識符,只要獲得對象的句柄,我們就可以對對象進行任意的操作。
  2. 句柄不是指針,操作系統用句柄可以找到一塊內存,這個句柄可能是標識符,map的key,也可能是指針,看操作系統怎麼處理的了。fd算是在某種程度上替代句柄吧;Linux 有相應機制,但沒有統一的句柄類型,各種類型的系統資源由各自的類型來標識,由各自的接口操作。
  3. 在操作系統層面上,文件操作也有類似於FILE的一個概念,在Linux裏,這叫做文件描述符fd(File Descriptor),而在Windows裏,叫做句柄(Handle)(以下在沒有歧義的時候統稱爲句柄)。用戶通過某個函數打開文件以獲得句柄,此後用戶操縱文件皆通過該句柄進行。

粗暴的解釋

windowns中是handle,liunx類似的是fd,最早的windows開發書籍,handle是被翻譯成“把手”的。雖然不好聽,但是個人認爲相當傳神。

  1. 雖然你握住的只是把手,卻能拉動整扇門,而且你根本不用在意那門長什麼樣子
  2. 一扇門如果有多個把手,被不同的人(進程)握住,門往哪兒走就不好說了

設計這麼一個句柄的原因在於句柄可以防止用戶隨意讀寫操作系統內核的文件對象。無論是Linux還是Windows,文件句柄總是和內核的文件對象相關聯的,但如何關聯細節用戶並不可見。內核可以通過句柄來計算出內核裏文件對象的地址,但此能力並不對用戶開放。

在liunx中的句柄

在linux系統設計裏面遵循一切都是文件的原則,即磁盤文件、目錄、網絡套接字、磁盤、管道等,所有這些都是文件,在我們進行打開的時候會返回一個fd,即是文件句柄。

linux句柄fd不用了,都要close()。如果頻繁的打開文件,或者打開網絡套接字而忘記釋放就會有句柄泄露的現象。在linux系統中對進程可以調用的文件句柄數進行了限制,在默認情況下每個進程可以調用的最大句柄數是1024個,如果超過了這個限制,進程將無法獲取新的句柄,而從導致不能打開新的文件或者網絡套接字,對於線上服務器即會出現服務被拒絕的情況。

下面舉一個實際的例子,在Linux中,值爲0、1、2的fd分別代表標準輸入、標準輸出和標準錯誤輸出。在程序中打開文件得到的fd從3開始增長 fd具體是什麼呢?在內核中,每一個進程都有一個私有的“打開文件表”,這個表是一個指針數組,每一個元素都指向一個內核的打開文件對象。而fd,就是這個表的下標。當用戶打開一個文件時,內核會在內部生成一個打開文件對象,並在這個表裏找到一個空項,讓這一項指向生成的打開文件對象,並返回這一項的下標作爲fd。由於這個表處於內核,並且用戶無法訪問到,因此用戶即使擁有fd,也無法得到打開文件對象的地址,只能夠通過系統提供的函數來操作。

在C語言裏,普通文件讀寫的渠道則是FILE結構,不難想象,C語言中的FILE結構必定和fd有一對一的關係,每個FILE結構都會記錄自己唯一對應的fd。

在程序設計中,句柄是一種特殊的智能指針。當一個應用程序要引用其他系統(如數據庫、操作系統 )所管理的內存塊或對象時,就要使用句柄。

句柄與普通指針的區別:

    指針包含的是引用對象的內存地址,而句柄則是由系統所管理的引用標識,該標識可以被系統重新定位到一個內存地址上。這種間接訪問對象的模式增強了系統對引用對象的控制。

     在上世紀80年代的操作系統(如Mac OS 和Windows )的內存管理 中,句柄被廣泛應用。Unix 系統的文件描述符 基本上也屬於句柄。和其它桌面環境 一樣,Windows API 大量使用句柄來標識系統中的對象 ,並建立操作系統與用戶空間 之間的通信渠道。例如,桌面上的一個窗體由一個HWND 類型的句柄來標識。

    如今,內存容量的增大和虛擬內存算法使得更簡單的指針愈加受到青睞,而指向另一指針的那類句柄受到冷淡。儘管如此,許多操作系統仍然把指向私有對象的指針以及進程傳遞給客戶端的內部數組下標稱爲句柄。

快速理解標準IO、IO重定向、管道

下面內容參考:https://blog.csdn.net/fdl123456/article/details/103982657

上面提到每個進程都有一個file數組,裏面放的該進程用到的文件描述符,程序的文件描述符默認情況下 0 是輸入,1 是輸出,2 是錯誤。我們可以畫一幅圖:

對於一般的計算機,輸入流是鍵盤,輸出流是顯示器,錯誤流也是顯示器,所以現在這個進程和內核連了三根線。因爲硬件都是由內核管理的,我們的進程需要通過「系統調用」讓內核進程訪問硬件資源。PS:不要忘了,Linux 中一切都被抽象成文件,設備也是文件,可以進行讀和寫。如果我們寫的程序需要其他資源,比如打開一個文件進行讀寫,這也很簡單,進行系統調用,讓內核把文件打開,這個文件就會被放到files的第 4 個位置,對應文件描述符 3:

明白了這個原理,輸入重定向就很好理解了,程序想讀取數據的時候就會去files[0]讀取,所以我們只要把files[0]指向一個文件,那麼程序就會從這個文件中讀取數據,而不是從鍵盤:

同理,輸出重定向就是把files[1]指向一個文件,那麼程序的輸出就不會寫入到顯示器,而是寫入到這個文件中:

錯誤重定向也是一樣的,就不再贅述。

管道符其實也是異曲同工,把一個進程的輸出流和另一個進程的輸入流接起一條「管道」,數據就在其中傳遞,不得不說這種設計思想真的很巧妙:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章