從 0 開始學(xué)習(xí) Linux 系列之「11.IO 概述」

IO

版權(quán)聲明:本文為 cdeveloper 原創(chuàng)文章,可以隨意轉(zhuǎn)載,但必須在明確位置注明出處!

IO 概述

這篇文章主要介紹 Linux IO 的基本知識和學(xué)習(xí)方法,掌握這些再學(xué)習(xí) IO 操作會更加游刃有余,更加系統(tǒng)。

上層開發(fā)與 kenel 的關(guān)系

在學(xué)習(xí) Linux 的 IO 操作之前,我們先來了解下上層開發(fā)和 kernel 底層的關(guān)系,也就是說上層大體上是如何調(diào)用底層的。我們以在 Linux 上開發(fā)的 C 程序為例簡單介紹一下,因為這部分詳細(xì)介紹很復(fù)雜,而我們開發(fā)上層只需要了解基本的過程即可,對底層有興趣可以深入研究。

自頂向下

我們從上到下來看看一個 C 的 IO 程序是如何調(diào)用內(nèi)核方法的:

Linux C App -> glibc(C 庫)-> VFS(虛擬文件系統(tǒng))-> kernel function(內(nèi)核方法)

這只是以 C 程序為例,Linux 的 C 程序現(xiàn)在使用的是 GNU C Libary, glibc,但是 Linux 也支持不同的語言,通過類比可以知道,每種語言也應(yīng)該都提供了相應(yīng)的類庫。

更加簡單的理解可以說成:操作系統(tǒng)內(nèi)核提供功能的實現(xiàn),上層類庫將這些實現(xiàn)封裝成 API 庫供上層調(diào)用,如果某個庫需要跨平臺,那么這個庫的接口就需要符合一定的規(guī)則

例如標(biāo)準(zhǔn) C 庫 ANSI C 就是跨平臺的,它的接口標(biāo)準(zhǔn)由國際標(biāo)準(zhǔn)化組織(ISO)制定,你在 Linux 上用 ANSI C 寫的 C 程序在 Windows 上也能運行,因為 Windows 也支持 ANSI C

Linux IO 體系結(jié)構(gòu)

在學(xué)習(xí) IO 操作之前,我們也需要對 Linux 的 IO 系統(tǒng)有一個大致的了解,總體來說,Linux 的上層 IO 結(jié)構(gòu)有下面 3 個方面:

  1. 文件系統(tǒng) API:Linux 下有很多種文件系統(tǒng),但是為了統(tǒng)一接口,Linux 提供了 VFS,我們需要學(xué)會使用 VFS 的 API
  2. 驅(qū)動和總線:提供對硬件的操作接口,需要了解
  3. 設(shè)備類型:鍵盤,鼠標(biāo)等硬件 IO 設(shè)備,需要了解

Linux 下所有的設(shè)備都是文件,所以都可以使用文件系統(tǒng)的 API 來操作,一個基本的方式如下:

LinuxApp (open...) -> /dev/xxx -> VFS -> xFS -> 總線 -> 驅(qū)動 -> 硬件

這其中 VFS 提供的對多種不同的 FS 的統(tǒng)一接口非常重要,這使得上層 APP 只需調(diào)用統(tǒng)一的 API,而不用擔(dān)心當(dāng)前使用的是哪種文件系統(tǒng):

VFS

VFS(虛擬文件系統(tǒng)) 是抽象在計算機中的典型應(yīng)用

通用的 IO 操作

IO 操作即使是在不同的系統(tǒng)上也經(jīng)常提供下面這些功能(不是全部):

  1. 打開,關(guān)閉文件:open,close
  2. 讀,寫文件:read,write
  3. 控制文件:seek 移動文件指針等

這些基本上可以說是一個 IO 系統(tǒng)最基本的操作,其中打開,關(guān)閉,讀寫都是平常的必備操作。那么 Linux 的 IO 操作有沒有什么特別的地方呢?

Linux 的 IO 操作分類

Linux 的 IO 操作大致可以分為以下幾類:

  1. 標(biāo)準(zhǔn) IO:使用 ANSI C 提供的 API
  2. 底層 IO:使用 Posix C 提供的 API
  3. FS 文件系統(tǒng)接口:掌握訪問 FS 的 API
  4. 管道及 FIFO(先入先出隊列):用于進(jìn)程間通信
  5. Socket:比較特殊的 IO 操作,用于網(wǎng)絡(luò)訪問
  6. 底層終端接口(tty):字符終端也是一種 IO

在 IO 階段主要還是以標(biāo)準(zhǔn)和底層 IO 為主,其他的類別一般都在進(jìn)程,網(wǎng)絡(luò)中介紹。

Linux IO 數(shù)據(jù)結(jié)構(gòu)

開發(fā)上層 Linux IO 類型的程序,你首先需要理解下面這 3 個數(shù)據(jù)結(jié)構(gòu),它們非常重要,是一切操作的核心。

1. 文件描述符 FD

對于 Linux 內(nèi)核來說,一個打開的文件是一個文件描述符(File Description,F(xiàn)D)的引用,F(xiàn)D 是一個非負(fù)整數(shù)。當(dāng)打開一個現(xiàn)存的文件或者創(chuàng)建一個新文件時,內(nèi)核向進(jìn)程返回一個文件描述符,當(dāng)讀寫文件時,用 open 或 read 返回的文件描述符 fd 標(biāo)識該文件,將其作為參數(shù)傳送給 read 和 write 。

每個進(jìn)程都有默認(rèn)的 FD[0, 1, 2]

  1. STDIN_FILENO:標(biāo)準(zhǔn)輸入,F(xiàn)D = 0
  2. STDOUT_FILENO:標(biāo)準(zhǔn)輸出,F(xiàn)D = 1
  3. STDERR_FILENO:標(biāo)準(zhǔn)錯誤輸出,F(xiàn)D = 2

2. File 結(jié)構(gòu)

struct file 在內(nèi)核中其實就代表了一個實際的文件,我們需要了解其中比較重要的字段:

struct file {
    // 文件鏈表指針
    struct list_head f_list;
    
    // 文件對應(yīng)目錄結(jié)構(gòu)
    struct dentry *f_dentry;
    
    // 虛擬文件系統(tǒng)掛載點
    struct vfsmount *f_vfsmnt;
    
    // 文件操作函數(shù)指針
    struct file_operations *f_op;

    ...

    // 文件模式
    mode_t f_mode;

    // 文件 offset
    loff_t f_pos;
};

3. Files Structure

file_struct 保存了一個進(jìn)程打開的所有文件表的數(shù)據(jù)

struct file_struct {
    // 自動曾量
    atomic_t count;
    
    ...
    
    // 最大文件句柄數(shù)目
    int max_fds;

    // 最大的 fd 集合容量
    int max_fdset;

    // 下一個空閑的 fs
    int next_fd;
    ...
};

如何學(xué)習(xí) IO 操作?

給你 2 個最好的免費資源:

  1. glibc 官網(wǎng)
  2. Linux 自帶的 man 手冊,例如:man 2 open

最好的方法是看 GNU 的官方文檔和系統(tǒng)自帶的 man 手冊,我們已經(jīng)知道 Linux C 使用的是 glibc 庫,那么我們可以去 GNU 官網(wǎng)去查找這個庫,發(fā)現(xiàn)它是開源的并且提供了非常好的學(xué)習(xí)文檔,而 man 是 Linux 系統(tǒng)自帶的,用起來也非常簡單,例如 man 2 open 即可查看 open 函數(shù)的用法,介紹非常詳細(xì)。但是市面上的那些培訓(xùn)機構(gòu)卻只會教你如何使用 API,而不教你如何查找這些 API 的學(xué)習(xí)資料,實在有些可惜。

一個函數(shù)名可能對應(yīng)一個 shell 命令,當(dāng)你用 man open 發(fā)現(xiàn)沒找到函數(shù)定義時,試試 man 2 open 或者 man [n] open

如果你養(yǎng)成學(xué)習(xí)一種技術(shù),首先到它的官網(wǎng)去查找學(xué)習(xí)資料的好習(xí)慣,那么你的進(jìn)步會非常的快,相信我。因為沒有比官網(wǎng)的資料更權(quán)威的了,那些寫博客的也只不過是翻譯并加上一些自己的理解,說實話當(dāng)你自己看懂了那些英文文檔,你就不需要看任何博客了,因為你已經(jīng)找到了最好的「博客」。

如果你喜歡看英文那么你完全可以不看我之后更新的 IO 的內(nèi)容,因為我的內(nèi)容也是根據(jù)官網(wǎng)的文檔自己總結(jié)的,你英文能力強,完全可以看原汁原味的資料,我更加希望你能不依賴別人而學(xué)習(xí),一個人的進(jìn)步 90 % 要靠自己,何況我自己的理解可能也不太準(zhǔn)確呢。但是如果你的英文不太好,那么我建議你可以對照我的博客和官方文檔來看,慢慢養(yǎng)成看英文的好習(xí)慣,受益終生。

結(jié)語

概述講的太多就沒有意義了,這篇文章主要讓你對 IO 有一個基本的了解,最重要的是你要理解上層 APP 大體的執(zhí)行過程如何系統(tǒng)的學(xué)習(xí) IO 操作,養(yǎng)成看英文文檔的習(xí)慣,這才是這篇文章介紹的最重要的內(nèi)容,具體的 IO 操作的文章后面會有更新,敬請期待。

最后,感謝你的閱讀,我們下次再見 :)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容