1. 程式人生 > >Linux下的程序間通訊之管道

Linux下的程序間通訊之管道

在Linux下,每個程序各自有不同的使用者地址空間,任何一個程序的全域性變數在另一個程序中都看不到所以進 程之間要交換資料必須通過核心,在核心中開闢一塊緩衝區,程序1把資料從使用者空間拷到核心緩衝區,程序2再從核心緩衝區把資料讀走,核心提供的這種機制稱為程序間通訊(IPC,InterProcess Communication).
1、管道(pipe)
管道是一種最基本的IPC機制,由pipe函式建立:

#include <unistd.h>
int pipe(int filedes[2]);

調⽤用pipe函式時在核心中開闢一塊緩衝區(稱為管道)⽤用於通訊,它有⼀一個讀端一個寫端,然後通過filedes引數傳出給使用者程式兩個檔案描述符,filedes[0]指向管道的讀端,filedes[1]指向管道的寫端(很好記,就像0是標準輸入1是標準輸出一樣)。所以管道在使用者程式看起來就像一個開啟的檔案,通過read(filedes[0]);或者write(filedes[1]);向這個檔案讀寫資料其實是在讀寫核心緩衝區。pipe函式呼叫成功返回0,呼叫失敗返回-1。 開闢了管道之後如何實現兩個程序間的通訊呢?比如可以按下面的步驟通訊:
這裡寫圖片描述


在一個程序呼叫pipe函式建立管道,得到兩個檔案描述符指向讀端和寫段。
這裡寫圖片描述
程序呼叫fork()建立子程序,那麼子程序會繼承父程序的檔案描述符,所以子程序也有兩個檔案描述符指向管道兩端。因為管道只能進行單向通訊,所以關閉父程序的讀端和子程序的寫端(也可以關閉父程序寫端和子程序讀端)。如下圖
這裡寫圖片描述
這是建立管道進行通訊的過程,管道建立好之後再寫端寫入,在讀端就可以讀到寫入的資料。下面編寫程式碼進行測試。

  1 #include<stdio.h>                                                           
  2 #include<unistd.h>
3 #include<errno.h> 4 #include<string.h> 5 6 int main() 7 { 8 int _pipe[2]; 9 int ret=pipe(_pipe); //建立管道 10 if(ret==-1) 11 { 12 printf("create pipe error!"); 13 return 1; 14 } 15 16 pid_t id=fork(); //建立子程序 17 if(id<0
) 18 { 19 printf("fork error!"); 20 return 2; 21 } 22 else if(id==0) //子程序 23 { 24 close(_pipe[0]); //關閉讀端 25 int i=0; 26 char *_mesg_c=NULL; 27 while(i<100) 28 { 29 _mesg_c="i am child"; 30 write(_pipe[1],_mesg_c,strlen(_mesg_c)+1); 31 sleep(1); 32 i++; 33 } 34 } 35 else //父程序 36 { 37 close(_pipe[1]); //關閉寫端 38 char _mesg[100]; 39 int j=0; 40 while(j<100) 41 { 42 memset(_mesg,'\0',sizeof(_mesg)); 43 read(_pipe[0],_mesg,sizeof(_mesg)); 44 printf("%s\n",_mesg); 45 j++; 46 } 47 } 48 return 0; 49 }

執行結果如圖:
這裡寫圖片描述
其中“i am child”每隔一秒列印一次。

使⽤用管道需要注意以下4種特殊情況(假設都是阻塞I/O操作,沒有設定O_NONBLOCK標誌):
1. 如果所有指向管道寫端的檔案描述符都關閉了(管道寫端的引用計數等於0),而仍然有程序從管道的讀端讀資料,那麼管道中剩餘的資料都被讀後,再次read會返回0,就像讀到檔案末尾一樣。
2. 如果有指向管道寫端的檔案描述符沒關閉(管道寫端的引用計數大於0),而持有管道寫端的程序也沒有向管道中寫資料,這時有程序從管道讀端讀資料,那麼管道中剩餘的資料都被讀取後,再次read會阻塞,直到管道中有資料可讀了才讀取資料並返回。
3. 如果所有指向管道讀端的⽂檔案描述符都關閉了(管道讀端的引用計數等於0),這時有程序向管道的寫端write,那麼該程序會收到訊號SIGPIPE,通常會導致程序異常終止。
4. 如果有指向管道讀端的檔案描述符沒關閉(管道讀端的引用計數大於0),而持有管道讀端的程序也沒有從管道中讀資料,這時有程序向管道寫端寫資料,那麼在管道被寫滿時再次write會阻塞,直到管道中有空位置了才寫⼊入資料並返回。