日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

进程间通信笔记(2)—管道和FIFO

發(fā)布時間:2024/1/1 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 进程间通信笔记(2)—管道和FIFO 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

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í),也是把書中的代碼解包裹。。。

#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> void server(int ,int); void client(int ,int); const int MAXLINE = 1024;int main(int argc,char ** argv) {int pipe1[2];int pipe2[2];pid_t childpid;//創(chuàng)建兩個管道if(pipe(pipe1)<0)printf("pipe1 error\r\n");if(pipe(pipe2)<0)printf("pipe2 error\r\n");if((childpid = fork())==0) //子進(jìn)程{close(pipe1[1]);//關(guān)閉寫close(pipe2[0]);//關(guān)閉讀server(pipe1[0],pipe2[1]);return 0;}//父進(jìn)程close(pipe1[0]);//關(guān)閉讀close(pipe2[1]);//關(guān)閉寫client(pipe2[0],pipe1[1]);wait(NULL);return 0; }void client(int readfd,int writefd) {size_t len;ssize_t n;char buff[MAXLINE];//讀入路徑名if(fgets(buff,MAXLINE,stdin)==NULL){printf("fgets error\r\n");return ;}len=strlen(buff);if(buff[len-1]=='\n')len--;//路徑名寫入管道if(write(writefd,buff,len)<0){printf("write error\r\n");return ;}//接收文件中數(shù)據(jù),寫入到標(biāo)準(zhǔn)輸出while((n=read(readfd,buff,MAXLINE))>0)write(STDOUT_FILENO,buff,n);//STDOUT_FILENO 1 // STDOUT_FILENO=fileno(stdout); }void server(int readfd,int writefd) {int fd;ssize_t n;char buff[MAXLINE];if((n=read(readfd,buff,MAXLINE))<=0){printf("read error\r\n");return ;}buff[n]='\0';fd=open(buff,O_RDONLY);if(fd < 0){snprintf(buff+n,sizeof(buff)-n,": can't open, %s\r\n",strerror(errno));n=strlen(buff);write(writefd,buff,n);}//open error 錯誤信息返回else{//從文件中讀入數(shù)據(jù)并寫入管道while((n=read(fd,buff,MAXLINE))>0){write(writefd,buff,n);}close(fd);} }

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: mkfifo mypipe xxx@xxx: echo helloworld > mypipe

在另一終端:

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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。