管道有兩種:無名管道和有名管道。管道是半雙工通訊。管道只在內存上開闢空間,不會在磁盤上開闢空間。
半雙工通訊指數據可以沿兩個方向傳送,但同一時刻只能有一個方向的傳送
先來說說無名管道吧:
無名管道是由調用pipe函數創建的;函數原型如下:
#include <unistd.h> //頭文件
int pipe(int filedes[2]);//函數原型
返回值:成功返回0,出錯返回-1
參數filedes返回兩個文件描述符:filedes[0]爲讀而打開,filedes[1]爲寫而打開。
無名管道它們只能在具有公共祖先的進程之間使用。通常,一個管道由一個進程創建,然後該進程調用fork,此後父、子進程之間就可以應用該管道。
調用fork之後做什麼取決於我們想要有的數據流的方向。對於從父進程到子進程的管道,則父進程應關閉管道的讀端(fd[0]),
子進程則關閉寫端(fd[1]).對於從子進程到父進程的管道,則與之相反。
下面我們用代碼來簡單實現無名管道:
void main()
{
int fd[2];
pipe(fd);//創建無名管道,並且將fd[0]綁定爲讀,fd[1]綁定爲寫
pid_t pid = fork(); //創建子進程
assert(pid != -1);
//這是從子進程到父進程的管道
if(pid == 0)
{
close(fd[0]); //子進程關閉讀端
while(1)
{
printf("please input data: ");
fflush(stdout);
char buff[128] = {0};
fgets(buff, 128, stdin); //輸入數據到buff中
buff[strlen(buff) - 1] = 0;
if(strcmp(buff, "end") == 0) //以‘end’結束
{
break;
}
write(fd[1], buff, strlen(buff)); //將buff中的數據寫入到管道中
}
close(fd[1]); //寫完關閉寫端
}
else
{
close(fd[1]); //父進程關閉寫端
while(1)
{
char buff[128] = {0};
int n = read(fd[0], buff, 127); //從管道讀端讀取數據,讀到buff中
if(n == 0)
{
break;
}
//打開一個文件a.txt,沒有的話在當前路徑下創建
int fda = open("a.txt", O_WRONLY | O_CREAT | O_APPEND, 0664);
assert(fda != -1);
write(fda, buff, n); //將buff中的數據寫到a.txt中
close(fda);//關閉文件
}
close(fd[0]); //讀完關閉管道的讀端
}
}
接下來我們看看有名管道(FIFO):
FIFO,管道只能由相關進程使用,這些相關進程的共同的祖先進程創建了管道。但是,通過FIFO,不相關的進程也能交換數據。
FIFO是一種文件類型。創建FIFO類似創建文件。
#include <sys/stat.h>
int mkfifo(const char *pathname,mode_t mode);
返回值,成功則返回0,出錯返回-1;
pathname:是創建的文件名字
mode:創建新文件時使用,eg:O_APPEND,O_CREAT (這個和open函數第三個參數一樣,具體見open參數)。
如果已經用mkfifo創建了一個FIFO,就可用open打開它。
當打開一個FIFO時,非阻塞標誌(O_NONBLOCK)會產生下列影響。
沒有指定O_NONBLOCK:open使用時會阻塞運行:如果只有只讀打開或者只寫打開的時候,open函數會阻塞,直到另一個進程以另一種方式打開此文件。
指定了O_NONBLOCK,則只讀的open會立即返回。但是,如果沒有進程已經爲讀而打開一個FIFO,name只寫open將會出錯返回-1.
read讀取數據時:如果沒有進程給管道里寫數據,read會阻塞,直到有數據或寫端關閉。
管道文件如果進行讀操作,讀了之後文件內存就清空,不存在了。
代碼簡單實現:
void main()
{
int fd = open("FIFO", O_WRONLY); //A進程以只寫的方式打開,open會阻塞,直到另一個進程以另一種方式打開
assert(fd != -1);
printf("fifo file open over\n");
sleep(1);
int n = write(fd, "hello word", strlen("hello word")); //往FIFO裏面寫了hello word
close(fd);
printf("data write file\n");
}
void main()
{
int fd = open("FIFO", O_RDONLY);//B進程以只讀打開
assert(fd != -1);
printf("fifo file open over\n");
char buff[128] = {0};
int n = read(fd, buff, 127); //從FIFO裏面讀數據,讀到buff中
close(fd);
printf("buff = %s\n", buff);
printf("data write file\n");
}
A進程會阻塞在open,等到B進程運行,以另一種方式打開FIFO時,A進程纔不阻塞,往下運行,寫入數據,B進程從FIFO管道文件中讀數據。