咱們以前瞭解過了 Linux 的進程和線程、Linux 內存管理,那麼下面咱們就來認識一下 Linux 中的 I/O 管理。緩存
Linux 系統和其餘 UNIX 系統同樣,IO 管理比較直接和簡潔。全部 IO 設備都被看成文件
,經過在系統內部使用相同的 read 和 write 同樣進行讀寫。網絡
Linux 中也有磁盤、打印機、網絡等 I/O 設備,Linux 把這些設備看成一種 特殊文件
整合到文件系統中,通常一般位於 /dev
目錄下。可使用與普通文件相同的方式來對待這些特殊文件。異步
特殊文件通常分爲兩種:socket
塊特殊文件是一個能存儲固定大小塊
信息的設備,它支持以固定大小的塊,扇區或羣集讀取和(可選)寫入數據。每一個塊都有本身的物理地址
。一般塊的大小在 512 - 65536 之間。全部傳輸的信息都會以連續
的塊爲單位。塊設備的基本特徵是每一個塊都較爲對立,可以獨立的進行讀寫。常見的塊設備有 硬盤、藍光光盤、USB 盤與字符設備相比,塊設備一般須要較少的引腳。async
塊特殊文件的缺點基於給定固態存儲器的塊設備比基於相同類型的存儲器的字節尋址要慢一些,由於必須在塊的開頭開始讀取或寫入。因此,要讀取該塊的任何部分,必須尋找到該塊的開始,讀取整個塊,若是不使用該塊,則將其丟棄。要寫入塊的一部分,必須尋找到塊的開始,將整個塊讀入內存,修改數據,再次尋找到塊的開頭處,而後將整個塊寫回設備。ide
另外一類 I/O 設備是字符特殊文件
。字符設備以字符
爲單位發送或接收一個字符流,而不考慮任何塊結構。字符設備是不可尋址的,也沒有任何尋道操做。常見的字符設備有 打印機、網絡設備、鼠標、以及大多數與磁盤不一樣的設備。工具
每一個設備特殊文件都會和 設備驅動
相關聯。每一個驅動程序都經過一個 主設備號
來標識。若是一個驅動支持多個設備的話,此時會在主設備的後面新加一個 次設備號
來標識。主設備號和次設備號共同肯定了惟一的驅動設備。性能
咱們知道,在計算機系統中,CPU 並不直接和設備打交道,它們中間有一個叫做 設備控制器(Device Control Unit)
的組件,例如硬盤有磁盤控制器、USB 有 USB 控制器、顯示器有視頻控制器等。這些控制器就像代理商同樣,它們知道如何應對硬盤、鼠標、鍵盤、顯示器的行爲。spa
絕大多數字符特殊文件都不能隨機訪問,由於他們須要使用和塊特殊文件不一樣的方式來控制。好比,你在鍵盤上輸入了一些字符,可是你發現輸錯了一個,這時有一些人喜歡使用 backspace
來刪除,有人喜歡用 del
來刪除。爲了中斷正在運行的設備,一些系統使用 ctrl-u
來結束,可是如今通常使用 ctrl-c
來結束。操作系統
I/O 的另一個概念是網絡
, 也是由 UNIX 引入,網絡中一個很關鍵的概念就是 套接字(socket)
。套接字容許用戶鏈接到網絡,正如郵筒容許用戶鏈接到郵政系統,套接字的示意圖以下
套接字的位置如上圖所示,套接字能夠動態建立和銷燬。成功建立一個套接字後,系統會返回一個文件描述符(file descriptor)
,在後面的建立連接、讀數據、寫數據、解除鏈接時都須要使用到這個文件描述符。每一個套接字都支持一種特定類型的網絡類型,在建立時指定。通常最經常使用的幾種
可靠的面向鏈接的字節流會使用管道
在兩臺機器之間創建鏈接。可以保證字節從一臺機器按照順序到達另外一臺機器,系統可以保證全部字節都能到達。
除了數據包之間的分界以外,第二種類型和第一種類型是相似的。若是發送了 3 次寫操做,那麼使用第一種方式的接受者會直接接收到全部字節;第二種方式的接受者會分 3 次接受全部字節。除此以外,用戶還可使用第三種即不可靠的數據包來傳輸,使用這種傳輸方式的優勢在於高性能,有的時候它比可靠性更加劇要,好比在流媒體中,性能就尤爲重要。
以上涉及兩種形式的傳輸協議,即 TCP
和 UDP
,TCP 是 傳輸控制協議
,它可以傳輸可靠的字節流。UDP
是 用戶數據報協議
,它只可以傳輸不可靠的字節流。它們都屬於 TCP/IP 協議簇中的協議,下面是網絡協議分層
能夠看到,TCP 、UDP 都位於網絡層上,可見它們都把 IP 協議 即 互聯網協議
做爲基礎。
一旦套接字在源計算機和目的計算機創建成功,那麼兩個計算機之間就能夠創建一個連接。通訊一方在本地套接字上使用 listen
系統調用,它就會建立一個緩衝區,而後阻塞直到數據到來。另外一方使用 connect
系統調用,若是另外一方接受 connect 系統調用後,則系統會在兩個套接字之間創建鏈接。
socket 鏈接創建成功後就像是一個管道,一個進程可使用本地套接字的文件描述符從中讀寫數據,當鏈接再也不須要的時候使用 close
系統調用來關閉。
Linux 系統中的每一個 I/O 設備都有一個特殊文件(special file)
與之關聯,什麼是特殊文件呢?
在操做系統中,特殊文件是一種在文件系統中與硬件設備相關聯的文件。特殊文件也被稱爲
設備文件(device file)
。特殊文件的目的是將設備做爲文件系統中的文件進行公開。特殊文件爲硬件設備提供了藉口,用於文件 I/O 的工具能夠進行訪問。由於設備有兩種類型,一樣特殊文件也有兩種,即字符特殊文件和塊特殊文件
對於大部分 I/O 操做來講,只用合適的文件就能夠完成,並不須要特殊的系統調用。而後,有時須要一些設備專用的處理。在 POSIX 以前,大多數 UNIX 系統會有一個叫作 ioctl
的系統調用,它用於執行大量的系統調用。隨着時間的發展,POSIX 對其進行了整理,把 ioctl 的功能劃分爲面向終端設備的獨立功能調用,如今已經變成獨立的系統調用了。
下面是幾個管理終端的系統調用
Linux 中的 IO 是經過一系列設備驅動實現的,每一個設備類型對應一個設備驅動。設備驅動爲操做系統和硬件分別預留接口,經過設備驅動來屏蔽操做系統和硬件的差別。
當用戶訪問一個特殊的文件時,由文件系統提供此特殊文件的主設備號和次設備號,並判斷它是一個塊特殊文件仍是字符特殊文件。主設備號用於標識字符設備仍是塊設備,次設備號用於參數傳遞。
每一個驅動程序
都有兩部分:這兩部分都是屬於 Linux 內核,也都運行在內核態下。上半部分運行在調用者上下文而且與 Linux 其餘部分交互。下半部分運行在內核上下文而且與設備進行交互。驅動程序能夠調用內存分配、定時器管理、DMA 控制等內核過程。可被調用的內核功能都位於 驅動程序 - 內核接口
的文檔中。
I/O 實現指的就是對字符設備和塊設備的實現
系統中處理塊特殊文件 I/O 部分的目標是爲了使傳輸次數儘量的小。爲了實現這個目標,Linux 系統在磁盤驅動程序和文件系統之間設置了一個 高速緩存(cache)
,以下圖所示
在 Linux 內核 2.2 以前,Linux 系統維護着兩個緩存:頁面緩存(page cache)
和 緩衝區緩存(buffer cache)
,所以,存儲在一個磁盤塊中的文件可能會在兩個緩存中。2.2 版本之後 Linux 內核只有一個統一的緩存一個 通用數據塊層(generic block layer)
把這些融合在一塊兒,實現了磁盤、數據塊、緩衝區和數據頁之間必要的轉換。那麼什麼是通用數據塊層?
通用數據塊層是一個內核的組成部分,用於處理對系統中全部塊設備的請求。通用數據塊主要有如下幾個功能
將數據緩衝區放在內存高位處,當 CPU 訪問數據時,頁面纔會映射到內核線性地址中,而且此後取消映射
實現
零拷貝
機制,磁盤數據能夠直接放入用戶模式的地址空間,而無需先複製到內核內存中管理磁盤卷,會把不一樣塊設備上的多個磁盤分區視爲一個分區。
利用最新的磁盤控制器的高級功能,例如 DMA 等。
cache 是提高性能的利器,無論以什麼樣的目的須要一個數據塊,都會先從 cache 中查找,若是找到直接返回,避免一次磁盤訪問,可以極大的提高系統性能。
若是頁面 cache 中沒有這個塊,操做系統就會把頁面從磁盤中調入內存,而後讀入 cache 進行緩存。
cache 除了支持讀操做外,也支持寫操做,一個程序要寫回一個塊,首先把它寫到 cache 中,而不是直接寫入到磁盤中,等到磁盤中緩存達到必定數量值時再被寫入到 cache 中。
Linux 系統中使用 IO 調度器
來保證減小磁頭的反覆移動從而減小損失。I/O 調度器的做用是對塊設備的讀寫操做進行排序,對讀寫請求進行合併。Linux 有許多調度器的變體,從而知足不一樣的工做須要。最基本的 Linux 調度器是基於傳統的 Linux 電梯調度器(Linux elevator scheduler)
。Linux 電梯調度器的主要工做流程就是按照磁盤扇區的地址排序並存儲在一個雙向鏈表
中。新的請求將會以鏈表的形式插入。這種方法能夠有效的防止磁頭重複移動。由於電梯調度器會容易產生飢餓現象。所以,Linux 在原基礎上進行了修改,維護了兩個鏈表,在 最後日期(deadline)
內維護了排序後的讀寫操做。默認的讀操做耗時 0.5s,默認寫操做耗時 5s。若是在最後期限內等待時間最長的鏈表沒有得到服務,那麼它將優先得到服務。
和字符設備的交互是比較簡單的。因爲字符設備會產生並使用字符流、字節數據,所以對隨機訪問的支持意義不大。一個例外是使用 行規則(line disciplines)
。一個行規能夠和終端設備相關聯,使用 tty_struct
結構來表示,它表示與終端設備交換數據的解釋器,固然這也屬於內核的一部分。例如:行規能夠對行進行編輯,映射回車爲換行等一系列其餘操做。
什麼是行規則?
行規是某些類 UNIX 系統中的一層,終端子系統一般由三層組成:上層提供字符設備接口,下層硬件驅動程序與硬件或僞終端進行交互,中層規則用於實現終端設備共有的行爲。
網絡設備的交互是不同的,雖然 網絡設備(network devices)
也會產生字符流,由於它們的異步(asynchronous)
特性是他們不易與其餘字符設備在同一接口下集成。網絡設備驅動程序會產生不少數據包,經由網絡協議到達用戶應用程序中。
UNIX 設備驅動程序是被靜態加載
到內核中的。所以,只要系統啓動後,設備驅動程序都會被加載到內存中。隨着我的電腦 Linux 的出現,這種靜態連接完成後會使用一段時間的模式被打破。相對於小型機上的 I/O 設備,PC 上可用的 I/O 設備有了數量級的增加。絕大多數用戶沒有能力去添加一個新的應用程序、更新設備驅動、從新鏈接內核,而後進行安裝。
Linux 爲了解決這個問題,引入了 可加載(loadable module)
機制。可加載是在系統運行時添加到內核中的代碼塊。
當一個模塊被加載到內核時,會發生下面幾件事情:第一,在加載的過程當中,模塊會被動態的從新部署。第二,系統會檢查程序程序所需的資源是否可用。若是可用,則把這些資源標記爲正在使用。第三步,設置所需的中斷向量。第四,更新驅動轉換表使其可以處理新的主設備類型。最後再來運行設備驅動程序。
在完成上述工做後,驅動程序就會安裝完成,其餘現代 UNIX 系統也支持可加載機制。
你好,我是 cxuan,我本身手寫了四本 PDF,分別是 Java基礎總結、HTTP 核心總結、計算機基礎知識,操做系統核心總結,我已經整理成爲 PDF,能夠關注公衆號 Java建設者 回覆 PDF 領取優質資料。
做者:cxuan 本文版權歸做者全部,未經做者容許不能轉載,轉載須要聯繫,不然追究法律責任的權利。 若是文中有什麼錯誤,歡迎指出。以避免更多的人被誤導。 |