管道(pipe)概述:(怎樣使用管道實現父子進程間通信)不相關的兩個進程無法通過無名管道進行進程間通信。
管道又稱無名管道(沒有名字),無名管道是一種特殊類型的文件,在應用層體現爲兩個打開的文件描述符。
管道是最古老的UNIX IPC方式,其特點是:
1> 半雙工,數據在同一時刻只能在一個方向上流動。(單工-收音機)
2> 數據只能從管道的一端寫入,從另一端讀出。
3> 寫入管道中的數據遵循先入先出的規則。
4> 管道所傳送的數據是無格式的,這要求管道的讀出方與寫入方必須事先約定好數據的格式,如多少字節算一個消息等。
5> 管道不是普通的文件,不屬於某個文件系統,只存在於內存中。
6> 管道在內存中對應一個緩衝區。不同的系統其大小不一定相同。
7> 從管道讀數據是一次性操作,數據一旦被讀走,它就從管道中被拋棄,釋放空間以便寫更多的數據。
8> 管道沒有名字,只能在具有公共祖先的進程之間使用。
Linuxshell允許重定向,而重定向使用的就是管道。例如:ls | more
創建管道的那個進程(父進程)具有管道的兩個文件描述符,繼承這個進程(子進程)也具有這兩個文件描述符,所以就可以對管道進行操作。父進程創建管道—>得到管道的兩個讀寫端->創建子進程,子進程繼承文件描述符(管道的兩個讀寫端)->父子進程進行進程間通信。
實際上,管道是一個固定大小的緩衝區,在linux中,該緩衝區的大小是4k(8×512Bytes),即一頁。
創建管道:
#include<unistd.h>
int pipe(int filedes[2]);
功能:經由參數filedes返回兩個文件描述符
參數:
>>filedes爲int型數組的首地址,其存放了管道的文件描述符filedes[0],filedes[1].
>>filedes[0]爲讀而打開,filedes[1]爲寫而打開管道,filedes[0]的輸出是filedes[1]的輸入。
返回值:成功返回0,失敗返回-1.
從管道中讀數據的特點:
1) 默認用read函數從管道中讀數據是阻塞的。
2) 調用write函數向管道里寫數據,當緩衝區已滿時write也會阻塞。
3) 通信過程中,讀端口全部關閉後,寫進程向管道內寫數據時,寫進程會(收到SIGPIPE信號)退出。
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc,char * argv[])
{
int fd_pipe[2];
char buf1[] = "hello world";
char buf2[15];
pid_t pid;
if(pipe(fd_pipe) < 0)
perror("pipe");
pid = fork();
if(pid < 0){
perror("fork");
exit(-1);
}
if(pid == 0){
write(fd_pipe[1],buf1,strlen(buf1));
_exit(0);
}else{
wait(NULL);//parent process,wait any child process's termination
memset(buf2,0,sizeof(buf2));
read(fd_pipe[0],buf2,sizeof(buf1));
printf("buf2 = [%s]\n",buf2);
}
return 0;
}
運行結果:
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc,char * argv[])
{
int fd_pipe[2];
char buf[] = "hello world";
pid_t pid;
if(pipe(fd_pipe) < 0)
perror("pipe");
pid = fork();
if(pid < 0){
perror("fork");
exit(-1);
}
if(pid == 0){
int i = 0;
close(fd_pipe[0]);
while(1){
write(fd_pipe[1],buf,strlen(buf));
i++;
printf("i = %d\n",i);
sleep(1);
}
_exit(0);
}else{
int i;
for(i = 0;i < 5;i++){
memset(buf,0,sizeof(buf));
read(fd_pipe[0],buf,sizeof(buf));
printf("read: buf = %s\n",buf);
}
close(fd_pipe[0]);
wait(NULL);//parent process,wait any child process's termination
}
return 0;
}
父子進程都關閉讀端之後,寫端也將自動關閉,運行結果如下: