如何理解「In UNIX, everything is a file」?


everything is a file (descriptor), but

  • 在 Linux 引入 signalfd 之前,signal 不是文件,你沒辦法用 poll 來等待 signal,只能用危險的 signal handler。

  • 在 FreeBSD 引入 pdfork 之前,子進程不是文件,你沒辦法用 poll 來等待子進程退出,只能 wait。也沒有辦法安全(race-free)地 kill 進程。Linux 不支持 pdfork。

  • 直到現在,線程也不是文件,你沒辦法用 poll 來等待線程退出,只能 join。Linux 的 clone_fd 似乎能以文件的方式管理子進程和線程,但還沒有進入 main stream。

  • Poll 也不能用於磁碟IO,Linux 不支持非阻塞的 file IO, 就算這個文件位於 NFS 上,也只能阻塞地讀。

算起來,只有 Sockets 才是真的可 poll 的 「好文件」啊。其實 select 本身也是跟 Sockets API 同時發明的(4.2 BSD,1983 年)。


說說我的理解吧。Unix 的 file 只是一個表現形式,其本質有兩點:

  • 統一的名字空間 (unified namespace):表現形式是文件系統 (filesystem) 的路徑;

  • 統一的訪問介面 (unified interface):表現形式是 read/write 等標準函數。

統一的名字空間保證了系統內各種資源都能用相同的方法發現;統一的訪問介面保證了這些資源都能以相似的方法進行操作。通過這兩點進而實現了以最小代價對系統內類型迥異的各種資源的調用。

這樣做的缺點也是很明顯的,因為要兼顧不同資源類型的不同屬性,所以訪問操作通常被定義為了最基礎最原始的字元串讀寫。顯然這不利於進行更高級別的抽象。大家對管道 (pipeline) 的抱怨也主要是因為這個。但這也是沒有辦法的事情,如果要建立更高級別的抽象,很多時候勢必會犧牲普遍性,前面講的那兩個統一也就不復存在了。


In UNIX,everything is a file, and everything has different open, close, read, write, ioctl, and poll……

要不是Windows那個WaitForMultipleObjects設計的太傻,還真可以驕傲的宣稱everything is pollable。


這是操作系統的思想。

反過來想想,性質各異的設備和信息,如何進行管理?

在操作系統提出不久後,就發生了軟體危機。

換作你,如何設計和實現操作系統?

分層是一種很自然的想法和方法。

更詳細的,請閱讀教材。


這就是面向對象思想啊。

用面向對象的是術語來說,UNIX的任何東西都直接/間接的繼承了「文件」這個基類(就好像所有的java類都繼承自object一樣);所以,它們都支持read/write之類操作。

當然,這個類體系並不是藉助某種面向對象語言提供的現成機制實現的。


「UNIX文件本質上就是一大袋位元組。」 —— 《UNIX編程藝術》

說穿了,文件是對IO的最簡抽象。


然而這個命題並不成立。因為沒有哪個unix和unix like的系統做到了everything is file。除了plan9,當初他們設計plan9就是為了真正實現everything is file,然而現在有多少人知道plan9吶?


嘗試回答一下。

在Unix中,任何可讀/寫也就是有I/O的設備,無論是文件,socket,驅動,在打開設備之後都有一個對應的文件描述符。Unix將對這些設備的讀寫簡化在read/write中。換言之,你只需要把打開的文件描述符傳給這兩個函數,操作系統內核知道如何根據這個文件描述符得到具體設備信息,內部隱藏了對各種設備進行讀寫的細節,所有這些對用戶都是透明的,你只需要打開它,得到fd,再進行相應的操作就夠了。API很簡單。


就是一句廢話,這麼普通的設計在當時可能有創新性,現在再提就給人一種沒什麼進步的感覺。


這就是Unix哲學。

Unix一貫主張Keep it simple。

把所有的設備都隱藏起來,給用戶統一的外在介面,操作起來簡潔方便。


文件就是位元組序列,系統中所有的輸入輸出其實都是通過UNIX I/O函數調用讀寫文件來實現的。

----深入理解計算機系統


個人理解,在windows中,文件是對磁碟的抽象,所有的文件/文件夾都會保存在磁碟上的某個位置

而在*nix種,文件是對IO的抽象,但IO不只局限於磁碟上

按The Art of UNIX Programming (豆瓣)中的話來說,Unix文件就是一大袋位元組,「一切都是位元組流」


In CS, every religion needs a slogan.


In unix, everything is a file, except makefail.


幾乎所有的設備,節點,句柄等,都有write,read這些文件所具有的操作介面


@Rio 講的是這樣設計的優劣。

個人認為「In UNIX, everything is a file」,應該這樣理解:

1 普通文件的讀寫,大家都可以理解吧, 讀寫,也就是輸入輸出, Input/Output

2 把這種IO 放到廣義的範圍,放到整個Unix中,所有的IO ,就像一個廣義的File


這個"everything"我理解為:用戶可見的東西。

可見的東西包括:文件,文件夾,鏈接,設備節點,套接字(socket)等等。如果按照簡單的思維,我們要不同的文件介面去處理不同文件類型,正如我們需要使用不同的網路協議去使用各種應用程序不同的應用一樣。但是Linux在處理這些文件的過程中,採用了一種Virtual File System(VFS)的抽象。這個抽象中最基本的一個抽象之一是inode。簡單來說這個inode包括了文件屬性(大小,訪問時間,許可權,==),而上面提到的這些類型,是建立在inode上的一個抽象(在C++中可以理解為基類,而文件的處理則繼承了這個基類)。所以當我們在操作一個「對象」(也就是everything中的某一員)時,實際時如下的調用:

文件

&>&>cp file ~/

shell找到cp命令,cp命令打開file(此時可能有io調用,系統根據file名字,在文件系統中查找file對應的inode,inode中包含文件屬性和inode號,根據inode號找到dentry,dentry就包含了file文件內容的磁碟塊號),然後執行拷貝動作。保存文件。

文件夾

&>&> tar czvf ~/ /tmp/

實際上文件夾和文件的處理方式是類似的,只不過在找到dentry後,文件的dentry中包含的是文件內容,而文件夾的dentry包含的是該目錄下的文件(夾)和inode的關係

鏈接

查找過程與文件類似。

設備節點

&>&>setty -F /dev/ttyUSB0

整個調用過程與文件類似。區別在於設備節點中inode指向的超級塊(super block,超級塊中包含文件系統的處理方法,也就是常見的file_operation)和文件不一樣。

套接字

套接字是基於inode更高一層的抽象來管理的。其數據結構為:

struct socket_alloc {

struct socket socket;

struct inode vfs_inode;

};

具體的過程就(wo)不(ye)詳(bu)述(zhi)了(dao)。

所以,綜上所述。無論是對於何種類型的文件,實際上都是使用了VFS這個高層虛構來管理這些東西。

若有不妥,歡迎大家拍磚。


這種思想是硬體底層所支持的,對於所有的I/O設備,對他們進行控制只是數據的讀入和讀出,早先的CPU的I/O指令只有兩個in和out,這很容易統一。對於CPU和內存來說,外部設備沒有差別。我們要做的就是將數據放入一塊內存區域,再將這塊區域數據放入數據匯流排,外部設備接收這些數據。文件描述符的作用就是指向這塊內存區域。

並不是操作系統將設備隱藏起來,而是計算機的體系結構已經將設備隱藏起來了。


在Unix 里,內存 硬碟 分區 鍵盤 滑鼠 音效卡 MIC 終端 光碟 管道 Socket 都是文件.


交互的本質就是輸入輸出IO,將所有的交互統一到成為文件IO


把內容換成in windows 也成立,大學彙編的知識,硬體上的一層封裝,不論是硬碟上的文件系統,各種硬體的通訊流,在該層上都是文件,windows看的不明顯,因為很少有人去看windows的命令行,看過點linux的,在命令行下,網卡,埠都是一個特殊的文件,會用特別的顏色標識。進題很淡定,看看回答就不淡定了,linux是很優秀,但有些特性windows也具備,就比如這個,上面的幾個回答整得好像linux是這樣,好高明,windows可能是比較低級的實現吧。至於這麼黑微軟么。


推薦閱讀:

為什麼有些Linux發行版更新地那麼頻繁?
Linux下有什麼工具可以分析出一個程序的運算時間分布嗎?
Linux為什麼要衍生出那麼多的版本,統一一下產品線不好么?
電腦小白怎樣在預裝了win8的電腦上安裝linux?
在 Linux 下學習 C 語言有什麼好處?

TAG:Linux | C編程語言 | Unix |