前面咱們講了進程間通訊的一種方式,匿名管道。
咱們知道,匿名管道只能用於父子關係的進程之間。那麼沒有這種關係的進程之間該如何進行數據傳遞呢?html
1.什麼是命名管道shell
匿名管道是在緩存中開闢的輸出和輸入文件流的空間,只能用於父子關係的進程之間。由於父子進程的輸入和輸出文件描述符是一致的。
命名管道是一種實際存在的FIFO文件,稱做「管道文件」,用於不一樣進程之間,命名管道進程間打開同一個FIFO文件,進行數據傳遞。
咱們能夠像普通文件同樣操做FIFO文件。
不一樣進程,引用同一個FIFO文件,進行數據傳遞。緩存
2.建立命名管道
mkfifo函數:建立一個命名管道函數
int mkfifo(const char *filename,mode_t mode);
filename:指定FIFO文件的名稱
mode:指定文件的讀寫權限spa
3.訪問命名管道
打開FIFO文件有四種方式:code
open(const char *filename,O_RDONLY); open(const char *filename,O_RDONLY|O_NONBLOCK); open(const char *filename,O_WRONLY); open(const char *filename,O_WRONLY|O_NONBLOCK);
須要注意的是,不能以O_RDWR模式打開FIFO文件,
由於這樣一個進程寫入的數據會被該進程讀取,FIFO通常只用作單向的數據傳遞。orm
open函數的第二個參數,表示是讀管道,仍是寫管道。
O_NONBLOCK表示FIFO管道的讀寫是非阻塞的,默認的話,是阻塞的。
那麼何爲阻塞呢?
一個進程寫模式打開管道的時候,必須有另外一個進程以讀模式打開;
或讀模式的時候,必須有另外一個進程寫寫模式打開,不然該進程open函數阻塞,直到知足以上關係。htm
非阻塞,意味着open函數會當即返回,若沒有其餘進程以只讀方式打開,open返回-1,而且FIFO也不會被打開。blog
4.FIFO管道使用示例
下例有兩個程序,fifowrite.c和fiforead.c分別寫管道和讀管道。
fifowrite.c中將一個文本文件data.txt,寫到管道。
fiforead.c中從管道讀取數據,並寫到dataformfifo.txt文件中。
程序使用了默認的阻塞模式。
示例代碼以下:進程
fifowrite.c
#include<sys/types.h> #include<stdlib.h> #include<stdio.h> #include<fcntl.h> #include<limits.h> int main() { const char *fifo_name = "/tmp/my_fifo"; int pipe_fd = -1; int data_fd = -1; int res = 0; const int open_mode = O_WRONLY; char buffer[PIPE_BUF+1]; if(access(fifo_name,F_OK)==-1) { res = mkfifo(fifo_name,0777); if(res!=0) { fprintf(stderr,"could not create fifo\n"); exit(EXIT_FAILURE); } } printf("process %d opening fifo O_WRONLY\n",getpid()); pipe_fd = open(fifo_name,open_mode); data_fd = open("data.txt",O_RDONLY); printf("process %d result %d\n",getpid(),pipe_fd); if(pipe_fd!=-1) { int bytes_read = 0; bytes_read = read(data_fd,buffer,PIPE_BUF); while(bytes_read>0) { res = write(pipe_fd,buffer,bytes_read); if(res==-1) { fprintf(stderr,"write error\n"); exit(EXIT_FAILURE); } bytes_read = read(data_fd,buffer,PIPE_BUF); buffer[bytes_read]='\0'; } close(pipe_fd); close(data_fd); } else{ exit(EXIT_FAILURE); } printf("process %d finished.\n",getpid()); exit(EXIT_SUCCESS); }
fiforead.c
#include<stdlib.h> #include<stdio.h> #include<sys/types.h> #include<fcntl.h> #include<limits.h> int main() { const char *fifo_name = "/tmp/my_fifo"; int pipe_fd = -1; int data_fd = -1; int res = 0; int open_mode = O_RDONLY; char buffer[PIPE_BUF+1]; int bytes_read = 0; int bytes_write = 0; memset(buffer,'\0',sizeof(buffer)); printf("process %d opening FIFO O_RDONLY\n",getpid()); pipe_fd = open(fifo_name,open_mode); data_fd = open("dataformfifo.txt",O_WRONLY|O_CREAT,0644); printf("process %d result %d\n",getpid(),pipe_fd); if(pipe_fd!=-1) { do{ res = read(pipe_fd,buffer,PIPE_BUF); bytes_write = write(data_fd,buffer,res); bytes_read +=res; }while(res>0); close(pipe_fd); close(data_fd); } else{ exit(EXIT_FAILURE); } printf("process %d finished,%d bytes read\n",getpid(),bytes_read); exit(EXIT_SUCCESS); }
輸出結果:
咱們在shell中輸入命令 ls -l /tmp/my_fifo查看FIFO管道文件的屬性
能夠看到,FIFO文件生成了,第一個字符‘p’,表示該文件是一個管道文件。
5.多個進程同時寫管道
當多個進程同時寫管道時,讀管道取得的數據是雜亂的。
此時,咱們能夠控制每一個進程,當要寫入的數據超過某個大小時,才寫管道,另外要以阻塞的方式打開FIFO。確保寫操做的原子性。