Linux 管道是什么 ?原理
簡(jiǎn)單點(diǎn)就是說,一個(gè)命令的結(jié)果作為另外一個(gè)命令(結(jié)果)的輸入 。
管道是linux提供的一種常見的進(jìn)程通信工具,也是很多shell命令能夠靈活組合產(chǎn)生強(qiáng)大用途的一個(gè)重要工具。
管道是什么?
管道,顧名思義就是個(gè)管子,里面可以流過去很多東西。舉個(gè)栗子ls | morels輸出列出來的文件目錄就通過‘|’這個(gè)管道流向了more這個(gè)文本瀏覽器。相同的功能我們也可以通過ls > tmp ; tmp > more來完成。實(shí)際上管道的功能和第二個(gè)方法也很像。管道也是一個(gè)文件ls的輸出送到這個(gè)文件,more再從這個(gè)文件將東西拿走。 所不同的是管道不同于普通的文件,是一套特殊的文件pipefs,在磁盤中沒有映像,只在內(nèi)存中存在,而且只存在于存在親緣關(guān)系的進(jìn)程之間。然后省略若干和文件系統(tǒng),linux進(jìn)程相關(guān)的知識(shí)…………好吧我還是說兩句吧。
為什么是特殊的文件?
我們知道有句傳說是linux系統(tǒng)中一切皆文件,事實(shí)上這句話很忽悠人,雖然都是文件一個(gè)文本文件能和一個(gè)CPU設(shè)備一樣么。實(shí)際上常用的特殊文件類型就有十多種,之所以要把他們都組織成文件是為了應(yīng)用級(jí)別的程序員編程方便,不管操縱什么東西,文件、設(shè)備、socket等等都可以open之后read,write再close,可事實(shí)上調(diào)用的底層的系統(tǒng)程序是不一樣的。這個(gè)想想也知道,寫一個(gè)文本用的實(shí)際操作和往一個(gè)socket寫東西怎么可能一樣。pipe特殊就在于它是進(jìn)程通信的一種方法,這種發(fā)法要保證一定的速度,所以就不好扔到硬盤上去讀寫了,干脆就直接在內(nèi)存上讀寫了,所以它成為一個(gè)文件只是為了接口的方便。至于說它只在有親緣關(guān)系的進(jìn)程間共享,是因?yàn)楣艿缹儆谶M(jìn)程打開的文件,只有創(chuàng)建管道的進(jìn)程fork出來的子進(jìn)程可以共享這個(gè)管道的文件描述符,其他無關(guān)系的進(jìn)程是看不到這個(gè)管道的,所以說是一種非常狹隘小資的通信方式。
管道的創(chuàng)建
管道有兩個(gè)口,一個(gè)入水口一個(gè)出水口。pipe系統(tǒng)調(diào)用會(huì)返回兩個(gè)文件描述符,一個(gè)文件描述符用來寫一個(gè)用來讀。如上圖所示,兩個(gè)file結(jié)構(gòu)指向同一個(gè)inode,對(duì)應(yīng)管道在內(nèi)存種所獲得的一片區(qū)域。這里稍微要注意的一點(diǎn)是,盡管我們平時(shí)的應(yīng)用都是一個(gè)管道對(duì)應(yīng)一個(gè)寫進(jìn)程一個(gè)讀進(jìn)程,但是管道本身是支持多個(gè)進(jìn)程進(jìn)行讀寫的,他們只要對(duì)相同的描述符進(jìn)行操作,加之系統(tǒng)的互斥進(jìn)程就可以實(shí)現(xiàn)多進(jìn)程的通信。這里也可以看出管道是半雙工的,沒有一個(gè)文件描述符可以用來進(jìn)行讀and寫,如果想在兩進(jìn)程間進(jìn)行全雙工操作就開兩條管道吧。
管道讀寫
前面說過了,不同的文件類型的write和read操作是不一樣的,那么是怎么通過一個(gè)統(tǒng)一的write和read來找到對(duì)應(yīng)的操作呢?看一下write函數(shù)的聲明size_t write(int fd, const void *buf, size_t nbytes),從進(jìn)程這邊傳過去的唯一一個(gè)可能區(qū)分文件類型的就是這個(gè)文件描述符fd了,也就是通過這個(gè)fd文件系統(tǒng)會(huì)找到它到底是哪個(gè)文件,再去采取相應(yīng)的函數(shù)調(diào)用。當(dāng)然如果是write操作的話還要涉及到一些對(duì)內(nèi)存加鎖的操作。
另一種管道FIFO
如果說管道有什么缺點(diǎn)的話,就是它只能在自家親戚中使用,不利于社會(huì)共同富裕,沒有關(guān)系的進(jìn)程就無法通過管道進(jìn)行勾搭了。于是內(nèi)核打算采用一種實(shí)名制的方式來登記一下管道,這就是FIFO。
FIFO和pipe用的是同樣的數(shù)據(jù)結(jié)構(gòu),同樣的讀寫方式,不同的是內(nèi)核為他們?cè)诖疟P注冊(cè)了一個(gè)節(jié)點(diǎn),這樣所有進(jìn)程都能看到這個(gè)硬盤上的節(jié)點(diǎn),只要有權(quán)限就可以操作了,當(dāng)然內(nèi)容還是在內(nèi)存中。并且這個(gè)實(shí)體可以用讀寫模式來打開,也就可以實(shí)現(xiàn)全雙工了。
其他的話
上面都是一些機(jī)制的介紹。其實(shí)想寫一下讀源碼的感受的,只是源碼的感受過于瑣碎,很難理出一個(gè)頭緒來,而且源碼的大框架是上面的機(jī)制,但看得時(shí)候注意到的更多是細(xì)節(jié)的實(shí)現(xiàn)方式,很多東西是和機(jī)制無關(guān)的。本以為這段的代碼變更應(yīng)該不會(huì)很大,但是看了一下commit記錄發(fā)現(xiàn)變化還是很多的,很多新加的功能是除了注釋找不到相關(guān)介紹的,只能自己從代碼里推敲。還有一些改進(jìn)方式是為了彌補(bǔ)以前的缺陷的,看這部分可以提升一些對(duì)系統(tǒng)整體的認(rèn)識(shí)。所以鼓勵(lì)大家在看過原理之后還是要看一下代碼,代碼中會(huì)有很多意外的收獲,而這些收獲又是很難通過別人講述獲得的
總結(jié)
以上是生活随笔為你收集整理的Linux 管道是什么 ?原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。