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