进程间通信(一)管道
一、概述
在Linux系統(tǒng)中,以進(jìn)程為單位來分配和管理資源。
由于保護(hù)的緣故,一個(gè)進(jìn)程不能直接訪問另一個(gè)進(jìn)程的資源,也就是說,進(jìn)程之間互相封閉。
在一個(gè)復(fù)雜的應(yīng)用系統(tǒng)中,通常會(huì)使用多個(gè)相關(guān)的進(jìn)程來共同完成一項(xiàng)任務(wù),因此要求進(jìn)程之間必須能夠互相通信,從而來共享資源和信息。
所以,一個(gè)操作系統(tǒng)內(nèi)核必須提供進(jìn)程間的通信機(jī)制。
管道
管道和有名管道是最早的進(jìn)程間通信機(jī)制之一,管道可用于具有親緣關(guān)系進(jìn)程間的通信,有名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關(guān)系進(jìn)程間的通信。
管道是指用于連接一個(gè)讀進(jìn)程和一個(gè)寫進(jìn)程,以實(shí)現(xiàn)它們之間通信的共享方式,又稱pipe文件。
管道是Linux支持的最初Unix IPC形式之一,具有以下特點(diǎn):
管道是半雙工的,數(shù)據(jù)只能向一個(gè)方向流動(dòng);需要雙方通信時(shí),需要建立起兩個(gè)管道;
只能用于父子進(jìn)程或者兄弟進(jìn)程之間(具有親緣關(guān)系的進(jìn)程);
單獨(dú)構(gòu)成一種獨(dú)立的文件系統(tǒng):管道對(duì)于管道兩端的進(jìn)程而言,就是一個(gè)文件,但它不是普通的文件,它不屬于某種文件系統(tǒng),而是自立門戶,單獨(dú)構(gòu)成一種文件系統(tǒng),并且只存在與內(nèi)存中。
數(shù)據(jù)的讀出和寫入:一個(gè)進(jìn)程向管道中寫的內(nèi)容被管道另一端的進(jìn)程讀出。寫入的內(nèi)容每次都添加在管道緩沖區(qū)的末尾,并且每次都是從緩沖區(qū)的頭部讀出數(shù)據(jù)。
管道是所有Unix都提供的一種IPC機(jī)制
一個(gè)進(jìn)程將數(shù)據(jù)寫入管道,另一個(gè)進(jìn)程從管道中讀取數(shù)據(jù)
在shell中使用管道的例子
命令:“l(fā)s | more”
使用pipeline “|”將兩個(gè)命令”ls”和“more”連接起來,使得ls的輸出成為more的輸入
也可以使用如下的兩個(gè)命令
命令1:“l(fā)s > tmp”
命令2:”more < tmp”
命令1把ls的輸出重定向到tmp文件中;
命令2把more的輸入重定向到tmp文件
創(chuàng)建管道
管道的創(chuàng)建:
#include <unistd.h>
int pipe(int fd[2])
該函數(shù)創(chuàng)建的管道的兩端處于一個(gè)進(jìn)程中間,在實(shí)際應(yīng)用中沒有太大意義,因此,一個(gè)進(jìn)程在由pipe()創(chuàng)建管道后,一般再fork一個(gè)子進(jìn)程,然后通過管道實(shí)現(xiàn)父子進(jìn)程間的通信。
注意:fd[0] 用于讀取管道,fd[1] 用于寫入管道。
管道讀寫
管道主要用于不同進(jìn)程間通信。實(shí)際上,通常先創(chuàng)建一個(gè)管道,再通過fork函數(shù)創(chuàng)建一個(gè)子進(jìn)程。
子進(jìn)程寫入和父進(jìn)程讀的命名管道:
管道的讀寫規(guī)則
管道兩端可分別用描述字fd[0]以及fd[1]來描述。
需要注意的是,管道的兩端是固定了任務(wù)的。即一端只能用于讀,由描述字fd[0]表示,稱其為管道讀端;另一端則只能用于寫,由描述字fd[1]來表示,稱其為管道寫端。
如果試圖從管道寫端讀取數(shù)據(jù),或者向管道讀端寫入數(shù)據(jù)都將導(dǎo)致錯(cuò)誤發(fā)生。
一般文件的I/O函數(shù)都可以用于管道,如close、read、write等等。
系統(tǒng)文件 write(fd[1],buf,size)
功能:把buf中的長度為size字符的消息送入管道入口fd[1]
fd[1]—pipe入口
buf:存放消息的空間
size :要寫入的字符長度
系統(tǒng)文件 read(fd[0],buf,size)
功能:從pipe出口fd[0]讀出size字符的消息置入 buf中。
fd[0]――Pipe的出口
進(jìn)程通信 管道 (pipe系統(tǒng)調(diào)用)
pipe(fd): 創(chuàng)建一個(gè)管道,fd[0]為管道的讀端;fd[1]為管道的寫端。 管道可用來實(shí)現(xiàn)父進(jìn)程與其子孫進(jìn)程之間的通信。管道以FIFO方式傳送消息。
#include <stdio.h> ...... main() { int x,fd[2]; char buf[30],s[30]; pipe(fd); /*創(chuàng)建管道*/ while((x=fork()) = = -1); /*創(chuàng)建子進(jìn)程失敗時(shí),循環(huán)*/ if(x = = 0) { sprintf(buf,“This is an example\n”); write(fd[1],buf,30); /*把buf中的字符寫入管道*/ exit(0); } wait(); read(fd[0],s,30); /*父進(jìn)程讀管道中的字符*/ printf(“%s”,s); }有名管道
管道應(yīng)用的一個(gè)重大限制是它沒有名字,因此,只能用于具有親緣關(guān)系的進(jìn)程間通信,在有名管道(named pipe或FIFO)提出后,該限制得到了克服。
FIFO不同于管道之處在于它提供一個(gè)路徑名與之關(guān)聯(lián),以FIFO的文件形式存在于文件系統(tǒng)中。這樣,即使與FIFO的創(chuàng)建進(jìn)程不存在親緣關(guān)系的進(jìn)程,只要可以訪問該路徑,就能夠彼此通過FIFO相互通信(能夠訪問該路徑的進(jìn)程以及FIFO的創(chuàng)建進(jìn)程之間)。
因此,通過FIFO不相關(guān)的進(jìn)程也能交換數(shù)據(jù)。值得注意的是,FIFO嚴(yán)格遵循先進(jìn)先出(first in first out),對(duì)管道及FIFO的讀總是從開始處返回?cái)?shù)據(jù),對(duì)它們的寫則把數(shù)據(jù)添加到末尾。
有名管道的創(chuàng)建
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char * pathname, mode_t mode)
該函數(shù)的第一個(gè)參數(shù)是一個(gè)普通的路徑名,也就是創(chuàng)建后FIFO的名字。
第二個(gè)參數(shù)與打開普通文件的open()函數(shù)中的mode 參數(shù)相同。
如果mkfifo的第一個(gè)參數(shù)是一個(gè)已經(jīng)存在的路徑名時(shí),會(huì)返回EEXIST錯(cuò)誤,所以一般典型的調(diào)用代碼首先會(huì)檢查是否返回該錯(cuò)誤,如果確實(shí)返回該錯(cuò)誤,那么只要調(diào)用打開FIFO的函數(shù)就可以了。一般文件的I/O函數(shù)都可以用于FIFO,如close、read、write等等。
有名管道比管道多了一個(gè)打開操作:open。
FIFO的打開規(guī)則:
如果當(dāng)前打開操作是為讀而打開FIFO時(shí),若已經(jīng)有相應(yīng)進(jìn)程為寫而打開該FIFO,則當(dāng)前打開操作將成功返回;否則,可能阻塞直到有相應(yīng)進(jìn)程為寫而打開該FIFO(當(dāng)前打開操作設(shè)置了阻塞標(biāo)志);或者,成功返回(當(dāng)前打開操作沒有設(shè)置阻塞標(biāo)志)。
如果當(dāng)前打開操作是為寫而打開FIFO時(shí),如果已經(jīng)有相應(yīng)進(jìn)程為讀而打開該FIFO,則當(dāng)前打開操作將成功返回;否則,可能阻塞直到有相應(yīng)進(jìn)程為讀而打開該FIFO(當(dāng)前打開操作設(shè)置了阻塞標(biāo)志);或者,返回ENXIO錯(cuò)誤(當(dāng)前打開操作沒有設(shè)置阻塞標(biāo)志)。
#include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> main() { char buffer[80]; int fd; char *FIFO=“pipe1”; mkfifo(FIFO,0666); if(fork()>0){ char s[ ] = "hello!\n";fd = open (FIFO,O_WRONLY); write(fd,s,sizeof(s)); close(fd); } else{ fd= open(FIFO,O_RDONLY);read(fd,buffer,80); printf("%s",buffer); close(fd); } }管道的局限性
從IPC的角度看,管道提供了從一個(gè)進(jìn)程向另一個(gè)進(jìn)程傳輸數(shù)據(jù)的有效方法。但是,管道有一些固有的局限性:
1.因?yàn)樽x數(shù)據(jù)的同時(shí)也將數(shù)據(jù)從管道移去,因此,管道不能用來對(duì)多個(gè)接收者廣播數(shù)據(jù)。
2.管道中的數(shù)據(jù)被當(dāng)作字節(jié)流,因此無法識(shí)別信息的邊界。
如果一個(gè)管道有多個(gè)讀進(jìn)程,那么寫進(jìn)程不能發(fā)送數(shù)據(jù)到指定的讀進(jìn)程。同樣,如果有多個(gè)寫進(jìn)程,那么沒有辦法判斷是它們中哪一個(gè)發(fā)送的數(shù)據(jù)。
轉(zhuǎn)載于:https://www.cnblogs.com/yanghaishu/archive/2012/05/10/2495201.html
總結(jié)
以上是生活随笔為你收集整理的进程间通信(一)管道的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【C++算法与数据结构学习笔记-----
- 下一篇: JSF框架在NetBeans下的编码