0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

你所不知道的linux匿名管道知識詳解

馬哥Linux運維 ? 來源:lq ? 2018-12-31 09:04 ? 次閱讀

相信很多在linux平臺工作的童鞋, 都很熟悉管道符 '|', 通過它, 我們能夠很靈活的將幾種不同的命令協(xié)同起來完成一件任務(wù)。就好像下面的命令:

不過這次咱們不來說這些用法, 而是來探討一些更加有意思的, 那就是管道兩邊的數(shù)據(jù)流"實時性"和管道使用的小提示。

其實我們在利用管道的時候, 可能會不經(jīng)意的去想, 我前一個命令的輸出, 是全部處理完再通過管道傳給第二個命令, 還是一邊處理一邊輸出呢? 可能在大家是試驗中或者工作經(jīng)驗中, 應(yīng)該是左邊的命令全部處理完再一次性交給右邊的命令進行處理, 不光是大家, 我在最初接觸管道時, 也曾有這么一個誤會, 因為我們通過現(xiàn)象看到的就是這樣。

但其實只要有簡單了解過管道這工具, 應(yīng)該都不難得出解釋:

管道是兩邊是同時進行, 也就是說, 左邊的命令輸出到管道, 管道的右邊將馬上進行處理。

管道的定義

管道是由內(nèi)核管理的一個緩沖區(qū),相當于我們放入內(nèi)存中的一個紙條。管道的一端連接一個進程的輸出。這個進程會向管道中放入信息。管道的另一端連接一個進程的輸入,這個進程取出被放入管道的信息。一個緩沖區(qū)不需要很大,它被設(shè)計成為環(huán)形的數(shù)據(jù)結(jié)構(gòu),以便管道可以被循環(huán)利用。當管道中沒有信息的話,從管道中讀取的進程會等待,直到另一端的進程放入信息。當管道被放滿信息的時候,嘗試放入信息的進程會堵塞,直到另一端的進程取出信息。當兩個進程都終結(jié)的時候,管道也自動消失。

管道工作流程圖

通過上面的解釋可以看到, 假設(shè) COMMAND1 | COMMAND2, 那么COMMAND1的標準輸出, 將會被綁定到管道的寫端, 而COMMAND2的標準輸入將會綁定到管道的讀端, 所以當COMMAND1一有輸出, 將會馬上通過管道傳給COMMAND2, 我們先來做個實驗驗證下:

在上面的命令, 我們可以猜測下輸出結(jié)果: 究竟是 睡眠6秒之后, 輸出"1111222", 還是輸出 "1111" 睡眠3秒, 再輸出 "2222", 然后再睡眠3秒, 再輸出"1111" 呢? 答案就是: 都不是! what! 這不可能, 大家可以嘗試下, 我們會看到終端沒反應(yīng)了, 為什么呢? 這就要涉及到文件IO的緩沖方式了,這里不多說, 簡單提一下文件IO的三種緩沖方式:

全緩沖:直到緩沖區(qū)被填滿,才調(diào)用系統(tǒng)I/O函數(shù), (一般是針對文件)

行緩沖: 遇到換行符就輸出(標準輸出)

無緩沖:沒有緩沖區(qū),數(shù)據(jù)會立即讀入或者輸出到外存文件和設(shè)備上(標準錯誤

因為python是默認采用帶緩沖的fputs,又因為標準輸出被改寫到管道, 所以將會采取全緩沖的方式(shell 命令具體要看實現(xiàn), 因為有些是用不帶緩沖write實現(xiàn),如果不帶緩沖區(qū),會直接寫入管道), 所以將會采取全緩沖的方式, 也就是說, 直到緩沖區(qū)被填滿, 或者手動顯示調(diào)用flush刷入,才能看到輸出。那我們可以將代碼改寫成下面兩種方式吧

輸出結(jié)果:

在這里我們已經(jīng)能夠得出結(jié)果, 如果像我們以前所想的那樣, 要等到COMMAND1全部執(zhí)行完才一次性輸出給COMMAND2, 那么結(jié)果應(yīng)該是無限堵塞。因為我的程序一直沒有執(zhí)行完。這樣應(yīng)該是不符合老前輩們設(shè)計初衷的, 因為這樣可能會導(dǎo)致管道越來越大。然而管道也是有大小的~ 具體可以去看posix標準, 所以我們得出結(jié)論是: 只要COMMAND1的輸出寫入管道的寫端(不管是緩沖區(qū)滿還是手動flush), COMMAND2都將立刻得到數(shù)據(jù)并且馬上處理。

那么管道兩邊的數(shù)據(jù)流"實時性"討論到就先暫告一段落, 接下來將在這個基礎(chǔ)上繼續(xù)討論:管道使用的小提示。

在開始討論前, 我想先引入一個專業(yè)術(shù)語, 也是我們偶爾會遇到的, 那就是:SIGPIPE。

或者是一個更加具體的描述:broken pipe(管道破裂)

上面的專業(yè)術(shù)語都是跟管道讀寫規(guī)則息息相關(guān)的, 那咱們來看下 管道的讀寫規(guī)則吧:

1.當沒有數(shù)據(jù)可讀時

O_NONBLOCK (未設(shè)置):read調(diào)用阻塞,即進程暫停執(zhí)行,一直等到有數(shù)據(jù)來到為止。

O_NONBLOCK ( 設(shè)置 ) :read調(diào)用返回-1,errno值為EAGAIN。

2.當管道滿的時候

O_NONBLOCK (未設(shè)置): write調(diào)用阻塞,直到有進程讀走數(shù)據(jù)

O_NONBLOCK ( 設(shè)置 ):調(diào)用返回-1,errno值為EAGAIN

3.如果所有管道寫端對應(yīng)的文件描述符被關(guān)閉,則read返回0

4.如果所有管道讀端對應(yīng)的文件描述符被關(guān)閉,則write操作會產(chǎn)生信號SIGPIPE

5.當要寫入的數(shù)據(jù)量不大于PIPE_BUF時,linux將保證寫入的原子性。

6.當要寫入的數(shù)據(jù)量大于PIPE_BUF時,linux將不再保證寫入的原子性。

在上面我們可以看到, 如果我們收到SIGPIPE信號, 那么一般情況就是讀端被關(guān)閉, 但是寫端卻依舊嘗試寫入

咱們來重現(xiàn)下SIGPIPE

這次執(zhí)行命令需要考驗手速了, 因為我們要趕在py醒過來之前, 將讀端進程殺掉

輸出結(jié)果

從上圖我們可以驗證兩個點:

當我們殺掉讀端時, 寫端會收到SIGPIPE而默認退出, 管道結(jié)束

當我們殺掉讀端時, 寫端的程序并不會馬上收到SIGPIPE, 相反的, 只有真正寫入管道寫端時才會觸發(fā)這個錯誤

如果寫入一個 讀端已經(jīng)關(guān)閉的管道, 將會收到一個SIGPIPE, 那讀一個寫端已經(jīng)關(guān)閉的管道又會這樣呢?

在上面也已經(jīng)證明了上文提到的讀寫規(guī)則:如果所有管道寫端對應(yīng)的文件描述符被關(guān)閉,將產(chǎn)生EOF結(jié)束標志,read返回0, 程序退出

總結(jié)

通過上面的理論和實驗, 我們知道在使用管道時, 兩邊命令的數(shù)據(jù)傳輸過程, 以及對管道讀寫規(guī)則有了初步的認識, 希望我們以后在工作時, 再接觸管道時, 能夠更加有把握的去利用這一強大的工具。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11161

    瀏覽量

    208460
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4256

    瀏覽量

    62223
  • 管道
    +關(guān)注

    關(guān)注

    3

    文章

    145

    瀏覽量

    17906

原文標題:你所不知道的linux匿名管道知識

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    Linux匿名管道和命名管道的區(qū)別

    數(shù)據(jù)。對于管道傳輸?shù)臄?shù)據(jù)是無格式的流且大小受限。對于管道來說,也分為匿名管道和命名管道,其中命名管道
    發(fā)表于 10-12 12:50 ?956次閱讀

    匿名管道是什么?有何功能?

    這是我第一次出教程,若不好可在評論回復(fù)我哦(?。?)~~~~~注:匿名管道是一個未命名的單相管道,通常用來在一個父進程和一個子進程之間的傳輸數(shù)據(jù)。匿名
    發(fā)表于 07-09 07:26

    Miniplayer小技巧 保證有不知道

    Miniplayer小技巧 保證有不知道的 1,用電源充電完成后先別拔充電器,先按住開關(guān)別放再拔開線就不用更新歌曲庫了。
    發(fā)表于 02-01 16:38 ?680次閱讀

    玩轉(zhuǎn)iPhone:可能不知道的iPhone實用技巧

    玩轉(zhuǎn)iPhone:可能不知道的iPhone實用技巧 玩iPhone有段時間了吧,怎么才能讓iPhone更順手呢?在這里可以看到一些最新的iPhone小技巧
    發(fā)表于 04-07 09:22 ?302次閱讀

    絕對有不知道的iOS自身小技巧!

    ?iOS本身就是一個很流暢,很人性化的系統(tǒng),但是功能多,一般使用的人有些功能并不知道如何使用。小編找了幾點小iOS自身的使用小技巧分享給大家。
    發(fā)表于 12-19 13:42 ?564次閱讀

    低功耗藍牙不知道怎么選型?看這里!

    低功耗藍牙不知道怎么選型?看這里!
    發(fā)表于 07-27 16:46 ?12次下載

    到底知不知道硬件設(shè)計是什么?

    想學(xué)習(xí)硬件電路方面的設(shè)計,但不知道怎么入手? 懵懵懂的進入硬件領(lǐng)域,對自己的發(fā)展和方向很迷茫? 做了一段時間硬件設(shè)計,事業(yè)發(fā)展和薪資遭遇瓶頸? 有時候必須承認,還不夠優(yōu)秀!甚至不知道
    的頭像 發(fā)表于 05-18 11:27 ?9650次閱讀

    關(guān)于可能不知道的printf

    可能不知道的printf
    的頭像 發(fā)表于 02-05 12:28 ?2552次閱讀
    關(guān)于<b class='flag-5'>你</b>可能<b class='flag-5'>不知道</b>的printf

    不知道的汽車蓄電池小知識

    哪些壞習(xí)慣會損壞蓄電池? 【知道不知道的蓄電池小知識】 ①:蓄電池使用兩年以上需注意檢查 一般汽車蓄電池的使用壽命為2-3年,新車的原裝蓄電池可以使用3年以上。所以如果
    的頭像 發(fā)表于 03-31 16:31 ?2540次閱讀
    <b class='flag-5'>你</b><b class='flag-5'>不知道</b>的汽車蓄電池小<b class='flag-5'>知識</b>

    如果不知道斜拉鏈機頭輪軸磨損怎么修,請看這里

    如果不知道斜拉鏈機頭輪軸磨損怎么修,請看這里
    發(fā)表于 06-16 14:55 ?1次下載

    Linux不知道的df命令的那些功能

    問題: 我知道Linux上我可以用df命令來查看磁盤使用空間。能告訴我df命令的實際例子使我可以最大限度得利用它嗎?
    的頭像 發(fā)表于 12-21 10:53 ?897次閱讀

    盤點不知道的電纜套管知識-科蘭

    電纜套管又稱保護管、導(dǎo)管,是在電氣安裝中用于保護電線、電纜布線的管道,允許電線、電纜的穿入與更換。電纜套管是電力工程中推廣使用的一種新型套管材料。盤點不知道的電纜套管知識,希望能夠得
    的頭像 發(fā)表于 05-25 10:24 ?1691次閱讀

    不知道的FPC,它的發(fā)展史竟然是這樣的!

    不知道的FPC,它的發(fā)展史竟然是這樣的!
    的頭像 發(fā)表于 11-15 10:48 ?925次閱讀

    揭秘pcb是什么物質(zhì):不知道的“化學(xué)戰(zhàn)士”

    揭秘pcb是什么物質(zhì):不知道的“化學(xué)戰(zhàn)士”
    的頭像 發(fā)表于 12-14 10:27 ?862次閱讀

    輥壓機軸承位磨損修復(fù)不知道的那些事

    電子發(fā)燒友網(wǎng)站提供《輥壓機軸承位磨損修復(fù)不知道的那些事.docx》資料免費下載
    發(fā)表于 03-12 15:10 ?0次下載