管道###
【11 章中筋量,我們看到一種在兩個進程間發(fā)送消息的非常簡單的方法: 使用信號岩灭;我們創(chuàng)建通知事件笆搓,通過它引起響應(yīng)膏蚓,但傳送的信息只限于一個信號值】
管道:通過它進程之間可以交換更有用的數(shù)據(jù)。
本章后:我們將學(xué)習(xí)到的知識將CD數(shù)據(jù)庫應(yīng)用程序重新實現(xiàn)為一個非常簡單的客戶/服務(wù)器應(yīng)用程序旷偿。
介紹大概:
(1)管道的定義
(2)進程管道
(3)管道調(diào)用
(4)父進程和子進程
(5)命名管道:FIFO
(6)客戶/服務(wù)器架構(gòu)
13.1 什么是管道烹俗?
當(dāng)從一個進程連接數(shù)據(jù)流到另一個進程時,我們使用術(shù)語:管道(pipe)萍程。
(我們通常是把一個進程的輸出通過管道連接到另一個進程的輸入)
大多數(shù)Linux的用于應(yīng)該早已對將shell命令連接在一起的概念很熟悉了幢妄,這實際上就是把一個進程的輸出直接傳遞給另外一個進程的輸入。(shell命令連接在一起茫负?蕉鸳??“|”)
eg: cmd1 | cmd2
對于shell命令倆說忍法,命令的連接是通過管道字符來完成的潮尝。【管道字符:“|”】
shell負責(zé)安排兩個命令的標(biāo)準輸入和標(biāo)準輸出
(1)cmd1 的標(biāo)準輸入來自終端的鍵盤
(2)cmd1 的標(biāo)準輸出傳遞給cmd2 饿序,作為它的標(biāo)準輸入勉失;
(3)cmd2的標(biāo)準輸出連接到終端屏幕。
. shell 所做的工作實際上就是對標(biāo)準輸入和標(biāo)準輸出流進行了重新連接原探,是數(shù)據(jù)連接從鍵盤輸入通過兩個命令最終輸出到屏幕上乱凿;
本章實現(xiàn)包含了 : 如何在程序中獲得這樣的效果,怎樣用管道將多個進程連接起來咽弦,從而實現(xiàn)一個簡單的客戶/服務(wù)器系統(tǒng)徒蟆。
13.2 進程管道###
兩個最簡單的在兩個程序之間傳遞數(shù)據(jù)的方法就是使用popen 和pclose 函數(shù)了。
頭文件: stdio.h
FILE *popen(const char *command, const cahr *open_mode);
int pclose(FILE *stream_to_close);
(1)popen 函數(shù)
popen 函數(shù)允許一個程序?qū)⒘硗庖粋€程序作為新進程啟動型型,并可以傳遞數(shù)據(jù)給它或者通過它接收數(shù)據(jù)段审。
command 字符串是要運行的程序名和相應(yīng)的參數(shù)。
open_mode 必須是“r”或“w”闹蒜;
如果open_mode 是“r”寺枉,被調(diào)用程序的輸出就可以被 調(diào)用程序使用抑淫,調(diào)用程序利用popen函數(shù)返回的FILE * 文件流指針,就可以通過常用的stdio庫函數(shù)(如:fread)來讀取被調(diào)用程序的輸出型凳;
如果open_mode 是“w”丈冬,調(diào)用程序就可以用fwrite 調(diào)用向被調(diào)用程序發(fā)送數(shù)據(jù),而被調(diào)通常用程序可以在自己的標(biāo)準輸入上讀取這些數(shù)據(jù)甘畅。被調(diào)用的程序通常不會意識到自己正在從另外一個進程讀取數(shù)據(jù),它只是在標(biāo)準輸入留上讀取數(shù)據(jù)往弓,然后做出相應(yīng)的操作疏唾。
每個popen調(diào)用都必須指定“r”或“w”,在popen函數(shù)的標(biāo)準實現(xiàn)中不支持任何其他選項函似。這意味著我們不能調(diào)用另外一個程序并同時對它進行讀寫操作(只可以選擇一個)槐脏。popen函數(shù)在失敗時返回一個空指針。如果想通過管道實現(xiàn)雙向通訊撇寞,最普通的解決方法是使用兩個管道顿天,每個管道負責(zé)一個方向的數(shù)據(jù)流。
(2)pclose函數(shù)####
用popen啟動的進程結(jié)束時蔑担,我們就可以用pclose函數(shù)關(guān)閉與之關(guān)聯(lián)的文件流牌废。##
pclose 調(diào)用值在popen啟動的進程結(jié)束后才返回。如果調(diào)用pclose時它仍然在云心啤握,pclose調(diào)用將等待該進程的結(jié)束鸟缕。
pclose 調(diào)用的返回值通常是它所關(guān)閉的文件流所在進程的退出碼。如果調(diào)用進程在調(diào)用pclose之前執(zhí)行了一個wait語句排抬,被調(diào)用進程的退出狀態(tài)就會丟失懂从,因為被調(diào)用進程已經(jīng)結(jié)束。此時蹲蒲,pclose將返回-1并設(shè)置errno為ECHILD番甩。
實驗:讀取外部程序的輸出###
下面的示例是在程序中用popen訪問uname命令給出的信息。
大概過程 : 完成程序的初始化工作后届搁,打開一個連接到uname命令的管道缘薛,把管道設(shè)置為可讀方式并讓read_fp 指向命令的輸出。最后咖祭,關(guān)閉read_fp指向的管道掩宜。
實驗解析: 這個程序用popen 調(diào)用啟動帶有-a選項的uname命令。然后用返回的文件流讀取最多BUFSIZge個字符(這個常量是stdio.h 中用#define 語句定義的)的數(shù)據(jù)么翰,并將它們打印出來顯示在屏幕上牺汤。因為我們是子啊程序內(nèi)部捕獲uname命令的輸出,所以可以處理它浩嫌。
實例代碼
13.3將輸出送往popen###
上面一個例子是捕獲外部程序輸出的例子檐迟;下面是將一個輸出發(fā)送到外部程序补胚。
這里是使用帶有參數(shù)“w”的popen 啟動od -c 命令,這樣就可以像該命令發(fā)送數(shù)據(jù)了追迟。然后它給od -c命令發(fā)送一個字符串溶其,該命令接受并且處理它,最后把處理結(jié)果打印到自己的標(biāo)準輸出上敦间。
相當(dāng)于:
代碼
13.3.1 傳遞更多的數(shù)據(jù)####
目前所使員工的數(shù)據(jù)通過一個fread 或fwrite 調(diào)用來發(fā)送或接受瓶逃; 有時,我們可能希望以塊的方式發(fā)送數(shù)據(jù)廓块,或者我們根本不知道輸出數(shù)據(jù)的長度厢绝。為了避免頂一個分廠大的緩沖區(qū),我們可以用多個fread或fwrite調(diào)用數(shù)據(jù)分為幾部分處理带猴。
這個程序調(diào)用了popen函數(shù)使用“r”參數(shù),和popen1.c 程序的做法一樣拴清。這一次我們是連續(xù)從文件流中讀取數(shù)據(jù)靶病,知道沒有數(shù)據(jù)讀取為止】谟瑁【注意:雖然ps命令的執(zhí)行要花費一些時間娄周,單linux會安排好進程間的調(diào)度,讓兩個程序可以運行時繼續(xù)運行】如果進程popen3沒有數(shù)據(jù)可讀苹威,它將被掛起知道數(shù)據(jù)到達昆咽。如果寫進程ps產(chǎn)生的輸出超過了可用緩沖區(qū)的長度,它也會被掛起知道讀進程讀取一些數(shù)據(jù)牙甫。
13.3.2如何實現(xiàn)popen###
請求popen調(diào)用運行一個程序時掷酗,它首先啟動shell,即系統(tǒng)中的sh命令窟哺,然后將command字符串作為一個參數(shù)傳遞給它泻轰。這有兩個效果,一個好一個不太好且轨。
在Linux(Unix) 中浮声,所有參數(shù)擴展都是由于shell來完成的。所以旋奢,啟動程序之前先啟動shell來分析命令字符串泳挥,就可以使各種shell擴展(eg:c所指的是哪些文件)。在程序啟動之前就會全部完成至朗。這個功能是非常有用的屉符,它允許我們通過popen啟動非常復(fù)雜的shell命令。而其他一些創(chuàng)建進程的函數(shù)(eg:execl)調(diào)用起來就復(fù)雜很多,因為調(diào)用進程必須自己去完成shell擴展矗钟。
使用shell不太好的影響是:針對每個popen調(diào)用唆香,不僅要啟動一個唄請求的程序,還要啟動一個shell吨艇,即每個popen調(diào)用將多啟動兩個進程躬它。從節(jié)省系統(tǒng)資源的角度來看,popen函數(shù)的調(diào)用成本略搞东涡,而且對目標(biāo)命令的調(diào)用比正常方式要慢一些冯吓。
下面的命令: cat popen.c | wc -l
shell在啟動后將popen*.c 擴展為一個文件列表,列表中的文件名都是以popen開頭软啼,以.c 結(jié)尾桑谍,shell還處理了管道符(|)并將cat命令的輸出傳遞給wc命令。我在一個popen調(diào)用中啟動了shell祸挪、cat 程序和wc程序,并進行了一次輸出重定向贞间。而調(diào)用這些命令的程序值看到最終的輸出結(jié)果贿条。
總結(jié)上面:
上面主要是關(guān)于什么是管道,就是進程之間的一種輸入和輸出的之間的信息交流增热。
進程管道的使用以及popen這個函數(shù)的使用整以。