网络与IO知识扫盲(一):Linux虚拟文件系统,文件描述符,IO重定向
系統IO原理
在 Linux 中:
VFS(Virtual Filesystem Switch):虛擬文件系統,是一個目錄樹。樹上不同的節點可以映射到物理的文件地址,可以掛載。
相當于一個解耦層,在具體的文件系統之上抽象的一層,為能夠給各種文件系統提供一個通用的接口,使上層的應用程序能夠使用通用的接口訪問不同文件系統、不同的驅動。
inode號:文件打開的時候有一個inode號,讀到pagecache頁緩存中。
兩個程序如果打開的是統一文件,共享的是同一個pagecache 4k。
如果后續我們對pagecache進行了修改,會產生臟數據,這時候需要使用flush刷新到磁盤中去。“臟”這個標識是內核對于上層打開的文件的一個統一的管理,并不是針對某一個文件。內核會根據自己的設定,把數據輸入到磁盤中去。如果你在5秒鐘內產生了3.8G數據,又恰好沒有觸發內核的寫磁盤操作,這時候突然斷電會導致你這些數數據的丟失。
如果兩個線程同時修改同一塊數據,會加鎖。
Redis的持久化,也是受操作系統內核這種機制的約束。
虛擬目錄樹
boot目錄在分區3中,其他目錄都在分區1中。
計算機引導的時候,先掛載了3分區,又掛載了1分區。新的掛載覆蓋了原有的boot目錄
虛擬文件系統進行了一個抽象:一切接文件。
磁盤文件、攝像頭、打印機,都被看做是文件,基于文件的這種抽象,就可以應用到IO流了。
那么如何區分這些不同的文件?我們引入文件類型:
硬鏈接
兩個變量名指向了同一個物理位置
無論是硬鏈接還是軟連接,如果修改任意一方,另外一個文件也會看到這個變化。
如果刪掉了其中一個文件,另外一方還能找到這個文件。相當于只是刪除了一個引用。
軟鏈接
軟鏈接是兩個獨立的文件。修改任意一個文件,另一個文件能看到這個變化。
如果刪除原有的msb.txt,則xxoo.txt找不到鏈接了,會標紅報錯。
如果刪除原有的msb.txt,則xxoo.txt找不到鏈接了,會標紅報錯。
下面我們開始搞事情,做一個小實驗,證明一切皆文件
用dd命令生成一個空的mydisk.img文件
掛載到虛擬的環回設備上,掛載之后進行格式化
把新的loop0掛載到原來的/mnt/ooxx目錄中去
現在/mnt/ooxx是空的
我們希望用子目錄模仿根目錄里面的目錄結構,以及程序的擺放位置。
1、找到bash所在位置,拷貝過來
2、將bash需要動態鏈接的文件,也拷貝過來
將根目錄切換到當前目錄,并將當前目錄下的bin下的bash啟動
在當前bash中輸出“hello mashibing”,重定向到根目錄下的abc,txt文件中
可以看到abc.txt被輸出到新的根目錄下。
那么Docker呢?也是這個原理嗎?
這個實驗不同于Docker,Docker更加復雜,它不只是文件系統的命名空間的一個子域。
Docker復用的是物理機的內核,Docker里面跑的是進程,先有鏡像,有了img鏡像之后,才有container容器的概念。
源于整個虛擬文件系統的支撐。
文件描述符
1、lsof命令
lsof是list open files的簡稱,它的作用主要是列出系統中打開的文件,基本上linux系統中所有的對象都可以看作文件,lsof可以查看用戶和進程操作了哪些文件,也可以查看系統中網絡的使用情況,以及設備的信息。
創建一個文件描述符8,用來讀取ooxx.txt
NODE列:表示Inode號
如果lsof加上-o參數的話,會顯示一列OFFSET,表示當前讀文件位置的指針。
使用read讀文件:
新開了一個bash標簽頁,用一個新的文件描述符6,去讀取ooxx.txt
證明兩個進程讀取文件時,不會相互影響:
我們可以得出這個結論,內核為每一個進程各自維護了一套數據,包括fd文件描述符。
fd維護了一些關于文件的偏移、Inode號,以及元數據信息等。
這些內容看起來和Java沒什么關系,但是在使用Java進行文件IO時,關系到每種不同的寫法的成本。所以還是很重要的~
Socket 文件類型示例
用文件描述符8,指向一個socket連接
關于/proc目錄
與其它常見的文件系統不同的是,/proc是一種偽文件系統(也即虛擬文件系統),存儲的是當前內核運行狀態的一系列特殊文件
/proc/$$ 是當前bash的文件
$$ BASHPID是當前bash的pid
/proc/$$/fd是當前程序的所有的文件描述符,也可以使用lsof -op $$看見當前進程的文件描述符的細節,包括偏移量、指針等等。
關于 0標準輸入 1標準輸出
<表示輸入 >表示輸出
ls 命令的標準輸出
ls ./ 1> ls.out將ls的標準輸出1重定向到ls.out
cat 命令的標準輸入、標準輸出
cat 0< test.txt 1> cat.out 將cat的標準輸入重定向為 test.txt , 將其標準輸出重定向為 cat.out
read命令的標準輸入、標準輸出
重定向操作符< >的對接
讓兩個流寫到不同的文件中去:
讓兩個流寫到相同的文件中去:
管道命令|
head 默認讀前 10 行
head -3 讀前 3 行
tail 默認讀后 10 行
tail -3 讀后 3 行
head -8 test.txt | tail -1 通過管道,讓左面的輸出流入右面的輸入,實現僅輸出第 8 行
Linux 前置知識
進程之間的父子關系
當前所在的bash的進程id號
在當前bash中新開一個bash,打印新開的bash的進程id號
使用pstree查看進程關系
使用exit,又回到了11053
關于變量
父進程定義的變量x,不能在子進程取到,除非使用export
這也是為什么在/etc/profile/配環境變量的時候,要添加export的原因
關于代碼塊、管道開啟的子進程
在一個花括號中,所有的指令在同一個進程中執行。
bash是解釋執行的,如果看到管道,會將管道左側的命令獨立開啟一個子進程,管道右側的命令獨立開啟一個子進程,用管道進行對接。而進程的隔離級別很高,所以在新開啟的進程中對變量a的修改,不會影響父進程a的值。
$$的優先級高于|,$BASHPID的優先級高于|
看一下進程號,可以發現管道兩側開啟的是獨立的子進程
實際上,我們進行的是如下管道操作:
下面這個圖可以看到,管道左側的進程和右側的進程通過管道被對接起來
我們也可以使用
lsof -op 4512
lsof -op 4513
這兩個命令,看到兩個子進程中正在開啟的管道。
PageCache
做完上面的鋪墊,我們可以先對PageCache做一個粗俗的理解了。
事實上,在很多地方都有緩存:
- 應用程序中:在application中可以有緩沖區(比如我們在Java中常用的BufferXXX IO)
- 內核中的頁緩存
- 硬盤上的緩沖區
如果每次應用程序想要讀數據的時候,都要通過cpu去取的話,效率會很低,于是我們了加入協處理器。
下面我們搞一個事情
寫一個mysh小腳本,待會兒使用的時候參數傳給0
OSFileIO.java
用上面的mysh啟動,傳參為0,也就是執行了testBasicFileIO()這個方法
測試突然斷電。斷電前我們看到,out.txt文件在不斷增大:
斷電后重啟,文件大小都是0:
上面這個測試說明了緩沖區的存在。在一段時間內,并沒有進行磁盤的刷寫。
總結
以上是生活随笔為你收集整理的网络与IO知识扫盲(一):Linux虚拟文件系统,文件描述符,IO重定向的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java程序员需要掌握的计算机底层知识(
- 下一篇: linux 其他常用命令