管道通訊機制
管道 pipe 是程序間通訊最基本的一種機制。在記憶體中建立的管道稱為無名管道,
在磁碟上建立的管道稱為有名管道。無名管道隨著程序的撤消而消失,有名管道則可
以長久儲存,shell 命令符| 建立的就是無名管道,而 shell 命令 mkfifo 建立的是有名
管道。兩個程序可以通過管道乙個在管道一端向管道傳送其輸出,給另一程序可以在
管道的另一端從管道得到其輸入.管道以半雙工方式工作,即它的資料流是單方向的.
因此使用乙個管道一般的規則是讀管道資料的程序關閉管道寫入端,而寫管道程序關
閉其讀出端。管道既可以採用同步方式工作也可以採用非同步方式工作。
對「讀管道資料的程序關閉管道寫入端,而寫管道程序關閉其讀出端」的理解:
用反證法的思想,假如寫管道的程序關閉管道寫入端,那麼,讀管道程序已經不想讀管道了,寫管道程序還在源源不斷地寫入資料,那麼管道是不是就會太慢而導致「炸裂」?,所以是讀管道程序關閉管道的寫入端。而寫管道的程序關閉讀出端,也很好理解,寫管道的程序不想寫了,它就關閉讀出端,讀管道程序讀完管道中剩餘的資料後自然也讀不到資料了。
上面這句話的意思是,讀管道資料的程序在讀資料之前要關閉管道寫入端,寫管道程序在寫資料之前關閉其讀出端,在讀管道資料的程序讀完資料之後,關閉管道的讀出端(0端),寫管道程序在寫完資料之後關閉其寫入端(1端)。
匿名管道的侷限性主要有兩點:一是由於管道建立在記憶體中,所以它的容量不可能很大;二是管道所傳送的是無格式位元組流,這就要求使用管道的雙方實現必須對傳輸的資料格式進行約定。
例子:在父子程序之間利用匿名管道通訊。
#include
#include
#include
#include
#define max_line 80
int main()
else
}return 0;pipe 系統呼叫的語法為:
#include
int pipe(int pipe_id[2]);
pipe 建立乙個無名管道,pipe_id[0]中和 pipe_id[1]將放入管道兩端的描述符,如果
pipe 執行成功返回 0。.出錯返回-1.
管道讀寫的系統呼叫語法為:
#include
ssize_t read(int pipe_id,const void *buf,size_t count);
ssize_t write(int pipe_id,const void *buf,size_t count);
read 和 write 分別在管道的兩端進行讀和寫。
pipe_id 是 pipe 系統呼叫返回的管道描述符。
buf 是資料緩衝區首位址,
count 說明資料緩衝區以 size_t 為單位的長度。
read 和 write 的返回值為它們實際讀寫的資料單位。
注意1.管道的讀寫預設的通訊方式為同步讀寫方式,即如果管道讀端無資料則讀者阻塞直到資料到達,反之如果管道寫端有資料則寫者阻塞直到資料被讀走。
注意2.上面說「buf 是資料緩衝區首位址」,這裡的資料緩衝區不要誤以為是管道對應一片資料緩衝區,而是,往管道裡寫入資料時,可以把已有的乙個資料緩衝區作為寫入資料的資料**,例如:這時的資料緩衝區可以是已經定義好內容的乙個字元陣列,那麼這是乙個「輸入資料緩衝區」或者「寫入資料緩衝區」,而從管道中讀出資料時,把讀出來的資料放在**呢?可以事先定義乙個字元陣列,然後把此陣列名作為引數傳入read()函式中,以便把讀出的資料存放在這個陣列中,那麼,這個陣列就相當於乙個"輸出資料緩衝區」/「讀出資料緩衝區」,第三個引數可以傳入資料緩衝區的大小(可以是你此前定義好的陣列的大小)
疑問:1.有管道的容量這個概念嗎?每次最多可以寫入或者讀出多少個資料呢?
答:好像沒有限制,讀多少都可以?是面向位元組流的。
命令 ulimit -a可以檢視管道的大小,這是核心設定的為8*512byte=4k bit
管道是一種最基本的程序間通訊機制。管道由pipe函式來建立:
synopsis
#include
int pipe(int pipefd[2]);
呼叫pipe函式,會在核心中開闢出一塊緩衝區用來進行程序間通訊,這塊緩衝區稱為管道,它有乙個讀端和乙個寫端。
pipe函式接受乙個引數,是包含兩個整數的陣列,如果呼叫成功,會通過pipefd[2]傳出給使用者程式兩個檔案描述符,需要注意pipefd [0]指向管道的讀端, pipefd [1]指向管道的寫端,那麼此時這個管道對於使用者程式就是乙個檔案,可以通過read(pipefd [0]);或者write(pipefd [1])進行操作。pipe函式呼叫成功返回0,否則返回-1。
只能單向通訊
只能血緣關係的程序進行通訊
依賴於檔案系統
4、生命週期隨程序
面向位元組流的服務
管道內部提供了同步機制
說明:因為管道通訊是單向的,在上面的例子中我們是通過子程序寫父程序來讀,如果想要同時父程序寫而子程序來讀,就需要再開啟另外的管道;
管道的讀寫端通過開啟的檔案描述符來傳遞,因此要通訊的兩個程序必須從它們的公共祖先那裡繼承管道的件描述符。 上面的例子是父程序把檔案描述符傳給子程序之後父子程序之 間通訊,也可以父程序fork兩次,把檔案描述符傳給兩個子程序,然後兩個子程序之間通訊, 總之需要通過fork傳遞檔案描述符使兩個程序都能訪問同一管道,它們才能通訊。(自己在實驗過程中發現,程式中不一定要有fork()才能使用管道,同乙個程序的多個執行緒也可以使用管道通訊)
四個特殊情況:
如果所有指向管道寫端的檔案描述符都關閉了,而仍然有程序從管道的讀端讀資料,那麼管道中剩餘的資料都被讀取後,再次read會返回0,就像讀到檔案末尾一樣
如果有指向管道寫端的檔案描述符沒關閉,而持有管道寫端的程序也沒有向管道中寫資料,這時有程序從管道讀端讀資料,那麼管道中剩餘的資料都被讀取後,再次read會阻塞,直到管道中有資料可讀了才讀取資料並返回。
如果所有指向管道讀端的檔案描述符都關閉了,這時有程序指向管道的寫端write,那麼該程序會收到訊號sigpipe,通常會導致程序異常終止。
如果有指向管道讀端的檔案描述符沒關閉,而持有管道寫端的程序也沒有從管道中讀資料,這時有程序向管道寫端寫資料,那麼在管道被寫滿時再write會阻塞,直到管道中有空位置了才寫入資料並返回。
從本質上說,管道也是一種檔案,但他又和一般的檔案有所不同,管道可以克服使用檔案進行通訊的兩個問題
使得他的大小不像檔案那樣不加檢驗的增長。使用固定緩衝區也會帶來問題,比如再寫管道時可能變滿
當這種情況發生時,隨後對管道的write()呼叫被阻塞,等待某些資料被讀取,以便騰出足夠的空間供
write()呼叫。
管道變空。這種情況發生時,乙個隨後的read()呼叫將被預設的阻塞,等待某些資料被寫入,這樣就解決了read()
C char 的一點兒理解
理解是就是char 相當於字串陣列,我以往糾結於該用 arr還是 arr還是 arr 還是 arr 對於 arr而言 arr代表陣列的最開頭,也就是第乙個字串的內容。arr代表什麼,不知道,這麼用會報錯。簡單的來說arr 0 代表第乙個字串的值,實際指向的整個 arr的首位址,如果用printf之類...
對C和C 的一點兒認識
今天在程式設計時,遇到一點問題。寫了一段程式,但是在編譯的時候,總報錯,顯示為某個變數沒有定義。中有這樣一句話 sockaddr in addr 經過試驗,編譯器是提示不認識這個變數sockaddr in 開始,我的每一感覺就是沒有包含標頭檔案,但是找來找去,發現標頭檔案沒有問題,於是開始想其它的辦...
技術人的一點兒思考
作為乙個技術人,雖然更多的是與機器和 打交道,但仍然也會有不少感觸和思考。安安靜靜的思考,平平淡淡的文字,寫下來,對自己也是一種總結和提公升,如果有幸能讓你看到,那,還真的很有緣。如果能帶給你啟發,就再好不過啦,哪怕只有一點點 別害怕技術焦慮 技術領域的迭代越來越快,新技術目不暇接。新的技術領域 新...