調用pipe函數時在內核中開闢一塊緩衝區(稱爲管道)用於通信,它有一個讀端一個寫端,然後通過filedes參數傳出給用戶程序兩個文件描述符,filedes[0]指向管道的讀端,filedes[1]指向管道的寫端(很好記就像0是標準輸入1是標準輸出一樣)。所以管道在用戶程序看起來就像一個打開的文通read(filedes[0]);或者write(filedes[1]);向這個文件讀寫數據其實是在讀寫內核緩衝區。 pipe函數調用成功返回0,調用失敗返回-1。 開闢了管道之後如何實現兩個進程間的通信呢?可以按下面的步驟通信。
1. 父進程調用pipe開闢管道,得到兩個文件描述符指向管道的兩端。
2. 父進程調用fork創建子進程,那麼子進程也有兩個文件描述符指向同一管道。
3. 父進程關閉管道讀端,子進程關閉管道寫端。父進程可以往管道里寫,子進程可以從管道里讀,管道是以環形隊列實現的,數據從寫端流入從讀端流出,這樣就實現了進程間通信。
代碼如下:
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
int main()
{
int pipe_fd[2]; //讀、寫
if(pipe(pipe_fd)<0)
{
printf("pipe error:%d",strerror(errno));
return 1;
}
pid_t id=fork();//創建管道
if(id==0)//child
{//write
close(pipe_fd[0]); //關掉讀端
char*str="hello bit\n";
int count=0;
while(1)
//while(count<5)
{
write(pipe_fd[1],str,strlen(str));
count++;
sleep(1);
// printf("write success:%d\n",count++);
}
close(pipe_fd[1]);
sleep(20);
}
else
{//read
close(pipe_fd[1]); //關掉寫端
char buf[1024];
//while(1)
int count=0;
while(count++<5)
{
//sleep(5);
buf[0]='\0';
ssize_t sz=read(pipe_fd[0],buf,sizeof(buf)-1);
if(sz>0)
{
buf[sz]='\0';
printf("father msg from child:%s\n",buf);
}
}
close(pipe_fd[0]);
sleep(20);
int status=0;
pid_t ret=waitpid(id,&status,0);
if(ret==id)
{
printf("wait sucess,get sig:%d\n,exit code:%d\n",status & 0xff,(status>>8) & 0xff); //低八位是退出信息,次低八位是退出碼(進程的退出碼範圍是0-255)
}
}
}
1. 如果所有指向管道寫端的文件描述符都關閉了(管道寫端的引用計數等於0),但仍然有進程從管道的讀端讀數據,那麼管道中剩餘的數據都被讀取後,再次read會返回0,就像讀到文件末尾一樣;
2. 如果有指向管道寫端的文件描述符沒關閉(管道寫端的引用計數大於0),但持有管道寫端的進程也沒有向管道中寫數據,這時有進程從管道讀端讀數據,那麼管道中剩餘的數據都被讀取後,再次read會阻塞,直到管道中有數據可讀了纔讀取數據並返回。
3. 如果所有指向管道讀端的文件描述符都關閉了(管道讀端的引用計數等於0),這時有進程向管道的寫端write,那麼該進程會收到信號SIGPIPE,通常會導致進程異常終止。
4. 如果有指向管道讀端的文件描述符沒關閉(管道讀端的引用計數大於0),但持有管道讀端的進程也沒有從管道中讀數據,這時有進程向管道寫端寫數據,那麼在管道被寫滿時再 次write會阻塞,直到管道中有空位置了才寫數據並返回。
有興趣的童鞋可以驗證一下!