概述
管道是 UNIX
系統(tǒng) IPC
的最古老的形式,所有的UNIX
系統(tǒng)都提供此種通信。所謂的管道,也就是內(nèi)核里面的一串緩存,從管道的一段寫(xiě)入的數(shù)據(jù),實(shí)際上是緩存在內(nèi)核中的,令一端讀取,也就是從內(nèi)核中讀取這段數(shù)據(jù)。對(duì)于管道傳輸?shù)臄?shù)據(jù)是無(wú)格式的流且大小受限。對(duì)于管道來(lái)說(shuō),也分為匿名管道和命名管道,其中命名管道也被叫做 FIFO,下面則分別闡述這兩種管道。
匿名管道
默認(rèn)情況下,在 Shell
命令執(zhí)行過(guò)程中,任何一個(gè)命令都有一個(gè)標(biāo)準(zhǔn)輸入設(shè)備(鍵盤(pán))、標(biāo)準(zhǔn)輸出設(shè)備(顯示器)和標(biāo)準(zhǔn)輸出設(shè)備(顯示器),使用管道"|"
可以將兩個(gè)命令連接起來(lái),從而改變標(biāo)準(zhǔn)的輸入輸出方式,下面是在 Linux 端運(yùn)行命令行的一個(gè)截圖:
上述命令中的意思也就是,將ls
命令得到的結(jié)果作為 grep tags
命令的輸入。
連接輸入輸出的中間設(shè)備即為一個(gè)管道文件,綜上,也就是說(shuō)使用管道可以將一個(gè)命令的輸出作為另一個(gè)命令的輸入(在運(yùn)行的時(shí)候,一個(gè)命令將創(chuàng)建一個(gè)進(jìn)程),而這種管道是臨時(shí)的,命令執(zhí)行完畢之后就會(huì)自動(dòng)消失,這類(lèi)管道稱(chēng)為 無(wú)名管道 。
匿名管道例子
匿名管道在使用前要先創(chuàng)建,其函數(shù)的聲明如下:
extern int pipe (int __pipedes[2]);
此函數(shù)的參數(shù)是一個(gè)整型數(shù)組,如果執(zhí)行成功,pipe 將存儲(chǔ)兩個(gè)整型文件描述符于__pipedes[0]
和__pipedes[1]
中,他們分別指向管道的兩端。如果系統(tǒng)調(diào)用失敗,則返回 -1。
讀無(wú)名管道,該函數(shù)的聲明如下:
extern ssize_t read (int __fd, void *__buf, size_t __nbytes);
第一個(gè)參數(shù)fd
為打開(kāi)的文件描述符,buf
為讀出數(shù)據(jù)的存儲(chǔ)位置,nbytes
為讀取數(shù)據(jù)的大小,調(diào)用 read 函數(shù)將從 fd 指向的文件描述符指定的打開(kāi)文件中宏讀 n
字節(jié)到 buf
指向的緩沖區(qū)內(nèi)。
如果試圖向已經(jīng)填滿的管道寫(xiě)入,系統(tǒng)會(huì)自動(dòng)阻塞。一個(gè)管道不能同時(shí)被兩個(gè)進(jìn)程打開(kāi)。
extern ssize_ t write(int __fd, __const void *__buf, size_t __n);
從 buf
指向的緩沖區(qū)中向管道中寫(xiě)入nbytes
字節(jié),且每次寫(xiě)入的內(nèi)容都附件在管道的末端。
那要如何使用管道在兩個(gè)進(jìn)程之間通信呢,我們可以使用 fork()
創(chuàng)建子進(jìn)程,創(chuàng)建的子進(jìn)程會(huì)復(fù)制父進(jìn)程的文件描述符,這樣就做到了兩個(gè)進(jìn)程各有兩個(gè)fd[0]與fd[1]
,兩個(gè)進(jìn)程就可以通過(guò)各自的fd
寫(xiě)入和讀取同一個(gè)管道文件實(shí)現(xiàn)進(jìn)程通信了,具體原理如下所示:
具體的例子如下所示:
#include
#include
#include
int main(int argc, char *argv[])
{
pid_t pid;
int temp;
int pipedes[2];
char s[14] = "test message!";
char d[14];
if (pipe(pipedes) == -1) // 創(chuàng)建管道
{
perror("pipe");
exit(EXIT_FAILURE);
}
if (pid == fork() == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
else if (pid == 0) // 子進(jìn)程
{
printf("now,write data to pipe\\n");
if (write(pipedes[1], s, 14) == -1) // 寫(xiě)數(shù)據(jù)到管道
{
perror("write");
exit(EXIT_FAILURE);
}
else
{
printf("the written data is:%s\\n",s);
exit(EXIT_SUCESS);
}
}
else if (pid > 0) // 父進(jìn)程
{
slepp(2);
printf("now, read from pipe\\n");
if ((read(pipedes[0], d, 14)) == -1)
{
perror("read");
exit(EXIT_FAILURE);
}
printf("the data from pipe is:%s\\n",d);
}
return 0;
}
代碼運(yùn)行的結(jié)果如下所示:
命名管道
命名管道又被稱(chēng)之為是 FIFO ,未命名的管道只能在兩個(gè)相關(guān)的進(jìn)程之間使用,而且這兩個(gè)相關(guān)的進(jìn)程還要又一個(gè)共同創(chuàng)建了他們的祖先進(jìn)程,但是,通過(guò) FIFO ,不相關(guān)的進(jìn)程也能交換數(shù)據(jù)。
首先,介紹下是如何創(chuàng)建命名管道的:
extern int mkfifo (__const char *__path, __mode_t __mode);
mkfifo
會(huì)根據(jù)參數(shù)建立特殊的有名管道文件,該文件必須不存在,而參數(shù)mode
為該文件的權(quán)限。
下面是一個(gè)使用命名管道進(jìn)行進(jìn)程間通信的例子,例子分為兩個(gè)程序,分別是讀部分和寫(xiě)部分,首先看先往管道寫(xiě)數(shù)據(jù)的代碼,代碼如下所示:
#include
#include
#include
#include
#include
#include
int main()
{
int fd;
// FIFO file path
char * myfifo = "/tmp/myfifo";
// Creating the named file(FIFO)
// mkfifo(, )
mkfifo(myfifo, 0666);
char arr1[80], arr2[80];
while (1)
{
// Open FIFO for write only
fd = open(myfifo, O_WRONLY);
printf("The fd is:%d\\n",fd);
// Take an input arr2ing from user.
// 80 is maximum length
fgets(arr2, 80, stdin);
// Write the input arr2ing on FIFO
// and close it
write(fd, arr2, strlen(arr2)+1);
close(fd);
// Open FIFO for Read only
fd = open(myfifo, O_RDONLY);
// Read from FIFO
read(fd, arr1, sizeof(arr1));
// Print the read message
printf("User2: %s", arr1);
close(fd);
}
return 0;
}
然后是先往管道讀數(shù)據(jù)的代碼,代碼如下所示:
#include
#include
#include
#include
#include
#include
int main()
{
int fd1;
// FIFO file path
char * myfifo = "/tmp/myfifo";
char str1[80], str2[80];
while (1)
{
// First open in read only and read
fd1 = open(myfifo,O_RDONLY);
printf("The fd is:%d\\n",fd1);
read(fd1, str1, 80);
// Print the read string and close
printf("User1: %s", str1);
close(fd1);
// Now open in write mode and write
// string taken from user.
fd1 = open(myfifo,O_WRONLY);
fgets(str2, 80, stdin);
write(fd1, str2, strlen(str2)+1);
close(fd1);
}
return 0;
}
下面是代碼運(yùn)行的一個(gè)結(jié)果:
說(shuō)明一下,就是說(shuō)當(dāng)運(yùn)行 write
程序的時(shí)候,會(huì)創(chuàng)建fifo
文件,命名管道,然后,在 write
文件中就執(zhí)行open
操作,但是,這里存在的一個(gè)問(wèn)題就是,因?yàn)樵谶\(yùn)行 write
程序的時(shí)候,沒(méi)有進(jìn)程打開(kāi)讀端,也就阻塞了 open
函數(shù)的運(yùn)行,只有運(yùn)行read
操作,以讀的方式讀取管道的數(shù)據(jù),這樣才能使得write
中的open
函數(shù)繼續(xù)執(zhí)行。
綜上,也就是命名管道在進(jìn)程中通信的一個(gè)例子。
小結(jié)
上述就是本次進(jìn)程通信中關(guān)于管道的相關(guān)內(nèi)容,其中就包括匿名管道以及命名管道,他們之間存在著差別嗎,也各有各的應(yīng)用,本次的分享就到這里啦~
-
UNIX
+關(guān)注
關(guān)注
0文章
296瀏覽量
41919 -
管道
+關(guān)注
關(guān)注
3文章
146瀏覽量
18125 -
IPC
+關(guān)注
關(guān)注
3文章
356瀏覽量
52586
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
Linux匿名管道和命名管道的區(qū)別
標(biāo)準(zhǔn)流管道
無(wú)名管道系統(tǒng)調(diào)用
命名管道FIFO讀寫(xiě)規(guī)則
匿名管道是什么?有何功能?
怎樣通過(guò)匿名管道去實(shí)現(xiàn)進(jìn)程間的通信呢
有名管道的相關(guān)資料分享
RT-Thread的管道有什么特點(diǎn)呢?怎么去使用
管道ADC,管道ADC原理及作用是什么?
水曖管道工實(shí)用手冊(cè)
Linux系統(tǒng)管道和有名管道的通信機(jī)制解析
Linux中的管道和命名管道介紹

你所不知道的linux匿名管道知識(shí)詳解

使用匿名管道技術(shù)獲取CMD命令的執(zhí)行結(jié)果
linux管道概述

評(píng)論