無名管道
無名管道是半雙工的,就是對於一個管道來講,只能讀,或者寫。
無名管道只能在相關的,有共同祖先的進程間使用(即一般用戶父子進程)。
一個fork或者execve調用創建的子進程繼承了父進程的文件描述符。
打開和關閉管道
int pipe(int filedes[2]);
在你從一個管道中讀出或者寫入數據,這個管道必須存在。
如果成功建立了管道,則會打開兩個文件描述符,並把他們的值保存在一個整數數組中。
第一個文件描述符用於讀取數據,第二個文件描述符用於寫入數據。
管道的兩個文件描述符相當於管道的兩端,一端只負責讀數據,一端只負責寫數據
如果出錯返回-1,同時設置errno
關閉一個文件描述符用close()函數
關閉一個管道的所有文件描述符等於關閉這個管道(不能讀不能寫)
pipe()函數打開管道一般不會失敗
讀寫管道
讀寫管道與讀寫普通文件方式一樣,調用write與read函數即可。
幾乎不會在一個進程中打開一個管道僅供進程自己使用,管道是用來交換數據的。
因為一個進程已經能夠訪問它要通過管道共享的數據,和自己共享數據是沒有意義的。
試圖對一個管道的某一端同時進行讀寫操作是一個嚴重的錯誤。
//無名管道
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int arg, char * args[])
{
//定義文件描述符數組
int fdarr[2] = { 0 };
int no = 0;
int status;
//create the conduit 創建一個管道 並且打開兩個文件描述符
//管道中,第一個文件描述符只讀,第二個文件描述符只寫
no = pipe(fdarr);
if (no == -1)
{
printf("pipe() is failed ! message :%s\n", strerror(errno));
return -1;
}
//創建父子進程
pid_t child = fork();
if (child == -1)
{
printf("system is game over !\n");
return -1;
}
//定義緩存字符串數組
char buf[100] = { 0 };
if (child == 0)
{
/*
管道和文件一樣,文件read函數以O_RDONLY方式打開也會阻塞,但是文件數據在本地,讀取非常快,感覺不到阻塞,
但是管道以O_RDONLY方式打開,會阻塞進程,read()函數會等待管道另一端寫入數據,直到另一端關閉文件描述符
*/
//關閉子進程中的寫文件描述符--對於父子進程共享文件描述符,只在單個進程中關閉,只能將文件描述符引用減一,
//因為父子進程中,文件描述符被引用了兩次,所以需要在父子進程中分別關閉,才能使文件描述符引用次數減一
close(fdarr[1]);
while (read(fdarr[0], buf, sizeof(buf)) > 0)
{
printf("%s", buf);
//清空緩存區
memset(buf, 0, sizeof(buf));
}
//關閉子進程中讀文件描述符
close(fdarr[0]);
} else
{
//關閉父進程中的讀描述符
close(fdarr[0]);
//將鍵盤輸入數據寫入到管道中
strcpy(buf,"fly on air!\n");
write(fdarr[1], buf, strlen(buf));
//關閉管道寫文件描述符
close(fdarr[1]);
//等待子進程結束
wait(&status);
printf("child process is close ! message :%d\n", WEXITSTATUS(status));
}
return 10;
}
