通過管道來實現程序間的通訊的方法很經典,因為多個程序共享3-4g中的核心,所以在核心中存在乙個管道(緩衝區),然後程序通過連線管道的兩端從而實現通訊。假如說我們現在有一根管道,我們從左端放入乙個小球,那麼它會從右端滾出來,那麼如果我們同時向兩端都放入乙個小球,那麼就不可能實現交叉傳遞了,所以管道是半雙工通訊(即雙方都可以傳送資訊,但是雙方不能同時傳送資訊),因此管道的兩端一端是讀端,一端是寫端。那麼要實現兩個程序的同時讀寫操作,就需要用兩個管道。
首先先來說一下pipe,這是乙個匿名管道(為啥叫匿名呢,下面講命名管道的時候就知道了),實現方式是迴圈佇列,它只能用於有血緣關係的程序間通訊。首先我們先來看一下pipe函式的原型:
#include int pipe(int pipefd[2]);
傳入的引數是乙個大小為2的陣列,然後就得到了兩個檔案描述符pipefd[0]和pipefd[1],前者用來指向管道的讀端,後者用來指向寫端。用乙個父子程序來舉例,如果要實現父子程序間的通訊,在fork前就需要建立乙個pipe管道,如果建立成功返回0,如果失敗返回-1並設定errno,由於子程序複製了父程序的pcb,所以子程序也有父程序的檔案描述符表,因此父子程序的pipefd都指向了同乙個pipe管道,然後我們要規定管道的傳輸方向,如果我們要求父寫子讀的話,我們就在父程序中close(pipefd[0]),在子程序中close(pipefd[1])就好了,建立好管道後我們通過write和read函式進行讀寫操作。
那麼在使用pipe通訊的時候可能會遇到以下的幾種情況:
1. 當讀管道時,如果管道中沒有資料,則會阻塞,直到管道另一端寫入資料。
2. 當寫管道時,如果管道中已經滿了,則會阻塞,直到管道另一端讀出資料(可見讀出資料時,管道中將不會保留該資料)。
3. 當管道寫端關閉時,讀端讀完管道內的資料時,如果再次去讀沒有資料的管道會返回0,相當於讀到了eof。
4. 當管道讀端關閉時,如果寫端在寫入資料時,產生sigpipe訊號,寫程序預設情況下會終止程序。
下面以父子程序的例子,來寫乙個程式來實現一下,**如下:
#include #include #include #include #include #include int main(void)
pid_t pid = fork();
// 父寫子讀 0讀端 1寫端
if(pid > 0)
else if(pid == 0)
else
return 0;
}
執行結果如下:
parent pid
hello child
我們可以用fpathconf來檢視管道的緩衝區大小,通過傳入檔案描述符和_pc_pipe_buf兩個引數來獲得乙個long整型的值。**如下:
printf("%ld\n", fpathconf(fd[0], _pc_pipe_buf));
還有就是我們可以通過設定o_nonblock引數來實現非阻塞的情況,也就是說當乙個程序還沒有寫資料時,另乙個讀程序就會阻塞在那裡,那麼如果設定了o_nonblock引數,該程序就不會阻塞在那裡,會返回-1,並設定errno為eagain,可以用goto語句或者while迴圈實現,那麼設定o_nonblock使用fcntl函式。
fifo用來建立乙個命名管道,可以解決非血緣關係的程序間通訊,它的底層的實現原理和匿名管道相同,只不過是生成了乙個可見的管道檔案。管道檔案用mkfifo命令來建立,如下圖所示:
這個管道檔案連線乙個在核心中的管道,那麼這個管道檔案對於所有的程序都是可見的,那麼程序通過開啟這個管道檔案就可以通過管道檔案所連線的管道來實現非血緣關係的程序間通訊了。因為這個管道有乙個所有程序都可以訪問到的管道檔案,所以fifo叫做命名管道,那麼同理,pipe就只能通過fork的方式來複製檔案描述符表來共享管道,而其他的程序卻訪問不到,所以叫做匿名管道。
下面也通過**,來簡單的實現一下fifo的效果,這裡我提前用mkfifo的命令來建立了乙個管道檔案,當然也可以在**中使用mkfifo函式來建立,先來看一下寫操作的程序的**:
#include #include #include #include #include #include #include int main(int argc,char *ar**)
char buf[1024] = "hello, i'm charles\n";
int fd = open(ar**[1], o_wronly);
if(fd == -1)
write(fd, buf, strlen(buf));
close(fd);
return 0;
}
下面是執行讀操作的**:
#include #include #include #include #include #include #include int main(int argc, char *ar**)
char buf[1024];
int fd = open(ar**[1], o_rdonly);
int len = read(fd, buf, sizeof(buf));
write(stdout_fileno, buf, len);
close(fd);
return 0;
}
然後我們開兩個終端去分別執行這兩個程式,我們先執行寫操作的程式,然後再執行讀操作的程式(當你執行寫操作的程式時會阻塞在write,當執行讀操作的程式時才會往下執行,這個就是上面所說的四種情況中的一種),最終結果如下: Linux程序間通訊 管道
linux程序間通訊機制 1.同一主機程序間通訊機制 unix方式 有名管道fifo 無名管道pipe 訊號signal systemv方式 訊號量 訊息佇列 共享記憶體 2.網路通訊 rpc remote procedure call socket 管道管道是程序間通訊中最古老的方式,它包括無名管...
Linux程序間通訊 管道
管道 管道是一種最基本的程序間通訊機制,由pipe函式建立 include intpipe int filedes 2 呼叫pipe函式時在核心中開闢一塊緩衝區 稱為管道 用於通訊,它有乙個讀端乙個寫端,然後通過filedes引數傳出給使用者程式兩個檔案描述符,filedes 0 指向管道的讀端,f...
Linux 程序間通訊 管道
程序間通訊 a程序怎樣將 hello world 傳遞給b程序 i 利用檔案實現 需要乙個 中間人 進行傳遞 檔案 在磁碟中儲存 a先呼叫open函式開啟檔案,再用write函式寫檔案,b用read函式讀取檔案,但問題如下 1.如果a傳送了資料b進行了接收,但a的資料沒有被清空 2.如果a傳送了資料...