linux系统管道知识,哈哈哈,好东西转给大家啦
原文鏈接地址:http://linchunai1212.blog.163.com/blog/static/35112143201111361543958/
前面在一段小程序中看到了mkfifo這樣的一個(gè)函數(shù),在baidu了一下之后對(duì)于進(jìn)程間通信產(chǎn)生了一點(diǎn)興趣,所以就小小的研究了一下。
在一個(gè)多進(jìn)程操作系統(tǒng)所提供的運(yùn)行環(huán)境下,可以通過兩種不同的途徑或者說采用兩種不同的策略,來建立起復(fù)雜的大型應(yīng)用系統(tǒng)。一種途徑就是通過一個(gè)孤立的, 大型的,復(fù)雜的進(jìn)程提供所需的全部服務(wù),另外一種途徑就是通過由若干相互聯(lián)系的,小型的。相對(duì)簡單的進(jìn)程構(gòu)成的組合來提供所需的功能。早期的操作系統(tǒng)往往 傾向與前者,而Unix以及其衍生的各種操作系統(tǒng)往往傾向于后者。相比之下,后者有著各種好處:1.模塊化,2.各個(gè)進(jìn)程都得到保護(hù),在相當(dāng)程度上排除了 相互干擾的可能性,3.靈活性更強(qiáng)。
當(dāng)然這種好處也是要付出代價(jià)的,也有缺點(diǎn),但是相比之下,這種途徑的優(yōu)點(diǎn)遠(yuǎn)遠(yuǎn)超出了其缺點(diǎn)。
Unix(從而Linux)向應(yīng)用軟件提供了一些進(jìn)程間通信的手段,早期的Unix提供了:管道(pipe),信號(hào)(signal),跟蹤(trace)。
這里我們只談管道:父進(jìn)程與子進(jìn)程,或者兩個(gè)兄弟進(jìn)程之間,可以通過系統(tǒng)調(diào)用建立起一個(gè)單向的通信管道。但是,這種管道只能由父進(jìn)程來建立,所以對(duì)于子進(jìn) 程來說是靜態(tài)的,與生俱來的。管道兩端的進(jìn)程各自將該管道視作一個(gè)文件。一個(gè)進(jìn)程往通道中寫的內(nèi)容由另一個(gè)進(jìn)程從通道讀出,通過通道傳遞的內(nèi)容遵循“先入 先出”(FIFO)的規(guī)則。每個(gè)通道都是單向的,需要雙向通信時(shí)要建立起兩個(gè)通道。
下面說一說進(jìn)程間管道的建立,在這之前我們要說到fork()函數(shù),在Linux系統(tǒng)中一個(gè)新的進(jìn)程是由一個(gè)已經(jīng)存在的進(jìn)程“復(fù)制”出來的,而不是“創(chuàng)造”出來的(而所謂的“創(chuàng)建”實(shí)際上就是復(fù)制)。
管道機(jī)制的主體是系統(tǒng)調(diào)用pipe(),但是由pipe()所建立的管道的兩端都在同一個(gè)進(jìn)程中,這樣的管道起不到進(jìn)程間通信的作用。所以必須在fork()的配合下,才能在父子進(jìn)程間或者兩個(gè)子進(jìn)程之間建立起進(jìn)程間的通信管道。
下面就介紹一下怎樣將管道用于進(jìn)程間通信:
(1)進(jìn)程A創(chuàng)建了一個(gè)管道,創(chuàng)建完成時(shí)代表管道兩端的兩個(gè)已打開文件都在進(jìn)程A中。
(2)進(jìn)程A通過fork()創(chuàng)建出進(jìn)程B,在fork()的過程中進(jìn)程A的打開文件表按原樣復(fù)制到進(jìn)程B中。
(3)進(jìn)程A關(guān)閉管道的讀端,而進(jìn)程B關(guān)閉管道的寫段。于是,管道的寫段在進(jìn)程A中而讀端在進(jìn)程B中,成為了父子進(jìn)程之間的通信管道。
?
(4)進(jìn)程A又通過frok()創(chuàng)建進(jìn)程C,而后關(guān)閉其管道寫段而與管道脫離關(guān)系,使得管道的寫段在進(jìn)程C中而讀端在進(jìn)程B中,成為兩個(gè)兄弟進(jìn)程之間的管道。
?
人們?cè)谡J(rèn)識(shí)到管道機(jī)制也存在一些缺點(diǎn)和不足。由于管道是一種“無名”,“無形”的文件,它可以通過fork()的過程創(chuàng)建于“近親” 的進(jìn)程之間,而不能成為可以在任意兩個(gè)進(jìn)程之間建立通信的機(jī)制,更不可能成為一種一般的,通用的進(jìn)程間通信模型,同時(shí),管道機(jī)制的這種缺點(diǎn)本身強(qiáng)烈的暗示 著人們,只要用“有名”,“有形”的文件來實(shí)現(xiàn)管道,就能克服這種缺點(diǎn)。所以有了管道之后,“命名管道”的出現(xiàn)時(shí)必然的。
為了實(shí)現(xiàn)“命名管道”,在“普通文件”,“塊設(shè)備文件”,“字符設(shè)備文件”之外,又設(shè)立了一種文件類型,稱為FIFO文件。對(duì)這種文件的訪問嚴(yán)格遵循“先進(jìn)先出”的原則。這樣就可以像在磁盤上建立一個(gè)文件一樣建立一個(gè)命名管道,具體可以使用命令mknod來建立。例如:
% mknod mypipe? ?p
這里的參數(shù)“p”表示所建立的節(jié)點(diǎn)的類型。
我們從——help中可以看出:
b? ?? ?create a block (buffered) special file
c, u? ?create a character (unbuffered) special file
p? ?? ?create a FIFO
一個(gè)使用pipe編程的例子
表頭文件 #include<unistd.h>
定義函數(shù) int pipe(int filedes[2]);
函數(shù)說明
pipe()會(huì)建立管道,并將文件描述詞由參數(shù) filedes 數(shù)組返回。
filedes[0]為管道里的讀取端,所以pipe用read調(diào)用的
filedes[1]則為管道的寫入端。
返回值:? 若成功則返回零,否則返回-1,錯(cuò)誤原因存于 errno 中。
錯(cuò)誤代碼:?
EMFILE 進(jìn)程已用完文件描述詞最大量
ENFILE 系統(tǒng)已無文件描述詞可用。
EFAULT 參數(shù) filedes 數(shù)組地址不合法。
#include <unistd.h>
#include <stdio.h>
int main( void )
{
int filedes[2];
char buf[80];
pid_t pid;
pipe( filedes );
if ( (pid=fork()) > 0 )
{
printf( "This is in the father process,here write a string to the pipe.\n" );
char s[] = "Hello world , this is write by pipe.\n";
write( filedes[1], s, sizeof(s) );
close( filedes[0] );
close( filedes[1] );
}
else
{
printf( "This is in the child process,here read a string from the pipe.\n" );
read( filedes[0], buf, sizeof(buf) );
printf( "%s\n", buf );
close( filedes[0] );
close( filedes[1] );
}
waitpid( pid, NULL, 0 );
return 0;
}
[root@localhost src]# gcc pipe.c?
[root@localhost src]# ./a.out?
This is in the child process,here read a string from the pipe.
This is in the father process,here write a string to the pipe.
Hello world , this is write by pipe.
總結(jié)
以上是生活随笔為你收集整理的linux系统管道知识,哈哈哈,好东西转给大家啦的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最佳睡眠计划
- 下一篇: 进程间通信的5种方式