Linux系統編程12 系統調用IO - 文件描述符實現原理

當我們使用 標準IO fopen 打開一個文件的時候,其實是調用的文件IO,即系統調用IO的 open來間接的打開文件,那他們之間是怎麼映射的呢?

當一個進程使用 標準IO fopen()打開一個文件的時候,會返回一個 FILE* 指針,我們用該指針對文件進行操作,說明該指針指向的結構體空間的某處內保存着已經打開文件的相關信息,比如當前位置信息。

而fopen 最終會調用文件IO open,即 fopen --> open ,當調用到文件IO open 的時候,也會生成一個結構體,該結構體保存着目標文件的相關信息。

那麼前面的問題:fopen()與open()之間是怎麼映射的,就可以理解爲是這兩個結構體之間是怎麼映射的。

說明:
首先每個進程都會有一個文件屬性結構體的指針數組,存放在該進程的進程空間。用於保存 文件IO open()所生成的 結構體地址。默認該數組的前三項,分別是 標準輸入,標準輸出,標準出錯。而後面的空間則用於保存該進程所打開的文件的相關信息結構體地址,即open()後,將得到的該文件的屬性結構體地址保存在進程文件屬性數組中,並將數組下標(即文件描述符)返回給 fopen()所生成的FILE結構體中對應位。這樣 fopen()就可以通過文件屬性結構體的指針數組的數組下標來訪問 open()得到的文件屬性結構體了。即文件描述符就是數組下標,一個int整形值。

在這裏插入圖片描述

整形數,數組下標,文件描述符優先使用當前可用範圍內最小的。

前面說到的每個進程的的文件屬性結構體指針數組,就是用來存儲該文件打開的所有的文件的屬性結構體地址,前面做了實驗,一個進程最多可以打開1024個文件,其中三個是標準輸入,標準輸出,標準錯誤,其餘1021就是所能打開的最多的文件數量,這裏的1024即 該進程文件屬性結構體指針數組的大小,可以通過 ulimit -n 命令修改該值,也就是修改數組的大小。注意,該數組 下標爲 0 1 2 的位置默認分別是 標準輸入,標準輸出,標準錯誤,也就是說 會默認打開三個設備標準輸入,標準輸出,標準錯誤,這三個設備會分別存放在0 1 2 的下標位置。其他開打的文件屬性結構體地址 從 下標爲3的地方開始 存放,並且存放的規則是 如果有下標較小的位置,則存放在 最小的下標位置。

情景1 :一個進程中打開兩個不同的文件:

對應的flose()的操作其實就是清空 open 得到的文件屬性結構體空間。
在這裏插入圖片描述

情景2:一個進程打開兩次同一個文件
會返回不同的文件描述符。同樣 fclose()的時候清除的是各自文件描述所對應的 文件屬性結構體,不會相互影響。

在這裏插入圖片描述

情景3:當一個進程的不同的文件描述符對應同一個文件屬性結構體

如下圖。該進程的文件描述4 和 6,即文件屬性結構體指針數組的下標4和6保存的是同一個文件屬性結構體的地址,這種情況,如果fclose()其中任意一個文件描述符,會不會馬上清除掉對應的 文件屬性結構體空間,也就是說如果關閉了4,那麼6會不會就成了一個野指針,就不能用了呢?答案是肯定不會的,如果是這樣的話那漏洞也太大了,那麼Linux 是怎麼應對這種情況的呢?因爲文件屬性結構體中有一個count計數器,他用來計算有多少個文件描述符對應自己,即被幾個指針所引用,每當有文件描述符 fclose的時候,count 就會自減1,直至count 自減至0,則清空該文件屬性結構體空間,否則不會清空。

在這裏插入圖片描述

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