进程间通信笔记(2)—管道和FIFO
1.概述
管道(pipe):局限在于沒有名字,只能用于親緣關(guān)系的進(jìn)程使用。
FIFO:稱為有名管道(named pipe)
2.客戶-服務(wù)器例子
跟套接字編程的套路類似,客戶-服務(wù)器回射程序:
這里客戶從標(biāo)準(zhǔn)輸入(stdin)讀入一個路徑名,并把它寫入IPC通道。服務(wù)器打開文件,讀出其中內(nèi)容,并寫入IPC通道作為對客戶的響應(yīng);客戶將服務(wù)器回射來的內(nèi)容打印即寫到標(biāo)準(zhǔn)輸出(stdout)。
3.管道
#include <unistd.h> int pipe(int fd[2]);pipe函數(shù)創(chuàng)建管道,并提供單向的數(shù)據(jù)流(不是全雙工哦,如果需要雙向數(shù)據(jù)流則需要創(chuàng)建兩個管道),該函數(shù)返回兩個文件描述符:fd[0]和fd[1]。前者用來讀,后者用來寫。
管道的典型應(yīng)用是用于父子進(jìn)程的通信,父進(jìn)程創(chuàng)建一個管道后調(diào)用fork派生出自己的副本,接著父進(jìn)程關(guān)閉管道的讀出端,子進(jìn)程關(guān)閉寫入端。這樣父子進(jìn)程間就有了一個單向的數(shù)據(jù)流,如下示意:
另外,在shell中使用“|”作為管道命令符,例如:
cat /etc/issue | grep Ubuntu在兩個進(jìn)程之間創(chuàng)建了一個管道,通過管道,前一個進(jìn)程的標(biāo)準(zhǔn)輸出傳遞給下一個進(jìn)程作為標(biāo)準(zhǔn)輸入。
3.1示例
下面實現(xiàn)一個經(jīng)典的管道示例,父進(jìn)程和子進(jìn)程之間完成通信,在主程序中創(chuàng)建兩個管道,用于雙向通信。父進(jìn)程為客戶,子進(jìn)程為服務(wù)器,第一個管道用于客戶向服務(wù)器發(fā)送路徑名,第二個管道用于服務(wù)器向客戶發(fā)送該文件內(nèi)容:
3.2代碼
通過創(chuàng)建兩個管道實現(xiàn)全雙工的通信:父進(jìn)程從標(biāo)準(zhǔn)輸入讀入文件的路徑名并寫入管道,子進(jìn)程從管道中讀出文件名并打開文件,讀出文件中的內(nèi)容寫入管道,父進(jìn)程從管道中接收文件中的內(nèi)容并寫入到標(biāo)準(zhǔn)輸出。
為了方便學(xué)習(xí),也是把書中的代碼解包裹。。。
4.FIFO
FIFO類似于管道,它是一個單向數(shù)據(jù)流,不同的是,FIFO有一個路徑名與之關(guān)聯(lián),從而允許無親緣關(guān)系的進(jìn)程訪問同一個FIFO,FIFO也被稱為有名管道(named pipe),使用mkfifo函數(shù)可以創(chuàng)建。
#include <sys/types.h> #include <sys/stat.h> int mkfifo(const char * pathname,mode_t mode); //成功返回0 出錯返回-1不僅僅是函數(shù),我們可以在shell下使用mkfifo創(chuàng)建有名管道。
例如:
在另一終端:
xxx@xxx: read line < mypipe xxx@xxx: echo $line使用fifo讓兩個無親緣關(guān)系的進(jìn)程進(jìn)行通信,由于每個fifo有一個路徑名與之關(guān)聯(lián),因此創(chuàng)建fifo后,需要使用I/O函數(shù)打開讀或者打開寫。
NOTE:fifo不能打開來既讀又寫,因為它是半雙工的。也就是說O_RDWR這種打開模式將是未定義的
示例代碼
在使用mkfifo函數(shù)的時候,需要注意一些問題:
1.mkfifo是隱含O_CREAT | O_EXCL也就是說,該函數(shù)要么創(chuàng)建一個FIFO(成功),要么返回一個EEXIST錯誤(失敗,該FIFO已經(jīng)存在),對于后者來說,它并不妨礙我們繼續(xù)使用這個已經(jīng)存在FIFO進(jìn)行通信。
2.關(guān)于創(chuàng)建的FIFO(所關(guān)聯(lián)的那個文件),需要說明讀寫權(quán)限,書中給了一個默認(rèn)權(quán)限:允許用戶讀寫、組內(nèi)成員和其他用戶讀,使用掩碼的方式包括起來就是:S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
下面就可以實現(xiàn)一個簡單的生產(chǎn)者消費者了,簡單起見,就只創(chuàng)建一個FIFO完成半雙工的通信了。
生產(chǎn)者
//fifowrite.c#include <stdio.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> int main(int argc,char** argv) {const char * const PATHNAME = "/home/zhangxiao/zxtest/pipe/myfifo";//關(guān)聯(lián)的路徑名const char * const BUFF = "Fifo Write Test.\r\n";int fd;if( (mkfifo(PATHNAME,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)<0) && (errno != EEXIST) ) {printf("can't create %s\r\n",PATHNAME);return -1;}fd = open(PATHNAME,O_WRONLY, 0);write(fd,BUFF,strlen(BUFF));return 0; }消費者
//fiforead.c#include <stdio.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h>int main(int argc,char** argv) {const int MAXLEN=1024;const char * const PATHNAME = "/home/zhangxiao/zxtest/pipe/myfifo";//關(guān)聯(lián)的路徑名ssize_t n;int fd;char readbuff[MAXLEN];memset(readbuff,0x00,sizeof(readbuff));//初始化if( (mkfifo(PATHNAME,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)<0) && (errno != EEXIST) ) {printf("can't create %s\r\n",PATHNAME);return -1;}fd = open(PATHNAME,O_RDONLY, 0);while( (n = read(fd,readbuff,sizeof(readbuff)))>0 ){write(STDOUT_FILENO,readbuff,n);//標(biāo)準(zhǔn)輸出}return 0; }5.參考
1.《UNP卷2》
2.http://stackoverflow.com/questions/25900873/write-and-read-from-a-fifo-from-two-different-script
總結(jié)
以上是生活随笔為你收集整理的进程间通信笔记(2)—管道和FIFO的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数字推理题725道详解
- 下一篇: 启锐电子面单驱动