管道是Linux裏的一種文件類型,同時也是Linux系統下進程間通信的一種方式
創建一個管道文件有兩種方式:
1. Shell 下命令 mkfifo + filename,即創建一個有名管道
2. C語言裏調用 pipe( ) 函數,創建一個無名管道
有名管道 / 無名管道
區別:
1. 有名管道在程序外部使用 mkfifo 命令生成,無名管道在程序內部調用 pipe( ) 函數創建;
2. 顧名思義,有名管道有文件名,無名管道沒有文件名;
3. 有名管道生成後直到刪除都存在,無名管道在程序退出時則生命週期結束;
4. 有名管道可以在任意兩個進程間傳輸數據,無名管道只能在父子進程間傳輸數據;
*有名/無名管道都是半雙工
(只能從一端向另一端發送數據,輸入端與輸出端在打開管道時是固定的)
管道文件的特性:
1. 打開管道必須有兩端(兩個進程)同時打開一個管道,分別爲讀(r)和寫(w);讀取端負責從管道中讀取數據,寫入端負責向管道中輸入數據;
2. 當讀端關閉,寫端會收到信號,終止程序;當寫端關閉,讀端不再進入阻塞;
3. 管道文件的大小始終爲0,打開管道文件時,在內存中爲其分配空間,管道關閉後數據消失;Linux默認PIPE_SIZE(一個管道最大存儲大小)爲64k,PIPE_BUF(管道緩衝區)爲4k;當對管道進行 write 操作時,若此時有多個進程同時寫入一個管道,且寫入的字節大小超過PIPE_BUF,則寫操作的數據有可能相互穿插。
管道文件的內存空間有兩個指針 head / tail ,head指針隨讀取數據向後移動,tail指針隨寫入數據向後移動,當指針到文件尾時,會造成讀阻塞 (讀取結束)/ 寫阻塞(空間已滿)
*注意*
當我們調用 pipe( ) 創建無名管道後 fork( ) 以實現父子進程間通信,此時 pipe( ) 生成的兩個 r / w 描述符引用都會加一,在父子進程中同時存在 r / w 兩個描述符,此時應當在父子進程中分別 close 不用的描述符,使 r / w 端只存在一個引用,這樣父子進程間通信時可以正常讀寫響應。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
char buff[128] = {0};
pid_t pid;
int pipefd[2];
pipe(pipefd); // creat & open a fifo file
pid = fork();
if(pid == -1)
{
printf("fork error\n");
exit(0);
}
else if(pid == 0) // chid process
{
close(pipefd[1]); // close 'w'
if( read(pipefd[0],buff,128) <= 0)
{
printf("read error\n");
exit(0);
}
printf("child : %s\n",buff);
}
else // parent process
{
close(pipefd[0]); // close 'r' fd
printf("input: ");
fflush(stdout);
gets(buff);
if( write(pipefd[1],buff,127) <= 0)
{
printf("write error\n");
exit(0);
}
}
close(pipefd[0]);
close(pipefd[1]);
exit(0);
}