簡述Linux進程間通信之命名管道FIFO
上文聊到管道(pipe),可以使有親緣關系的進程間進行通信.
對於沒有親緣關系的進程如何通信?本文來聊一聊命名管道FIFO.
一、概念
命名管道FIFO,提供一個路徑名與之關聯,以文件形式存儲於文件系統中.
一個進程以r方式打開,另一個程序以w方式打開,即可在兩個進程之間建立管道.
通過以fifo文件作為媒介,可以使任意兩個進程通過該文件進行通信.
命名管道(fifo)特性與管道(pipe)類似,不必贅述.
下面我們看FIFO如何進行進程間通信,首先來介紹一下所用到的函數:
二、函數原型
#include <sys/types.h> #include <sys/stat.h> int mknod(const char *path,mode_t mod,dev_t dev); int mkfifo(const char *path,mode_t mode);
函數mknod參數:
path:為創建的命名管道的全路徑名:
mod:為創建的命名管道的模式,指明其存取權限;
dev:為設備值,該值取決於文件創建的種類,它只在創建設備文件時才會用到.
函數mkfifo前兩個參數的含義和mknod相同.
這兩個函數調用成功都返回0,失敗都返回-1.
下面我來看一組實例,以server與client為例,server為接受端,client為發送端.
三、通信實例
server端:
#include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> int main(){ umask(0); //將umask設置為0 //創建管道文件,“S_IFIFO|0666”指明創建一個命名管道且存取權限為0666 if(mkfifo("./fifo",S_IFIFO|0666)==-1){ perror("mkfifo"); return 1; } //以只讀方式打開管道文件 int fd = open("./fifo",O_RDONLY); if(fd == -1){ perror("open"); return 2; } char buff[1024] = {0}; int i = 0; //接受消息 while(1){ ssize_t s = read(fd,buff,sizeof(buff)-1); buff[s] = 0; printf("server receive#%s\n",buff); } close(fd); return 0; }
client端:
#include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> int main(){ int fd = open("./fifo",O_WRONLY); if(fd == -1){ perror("open"); return 2; } char buff[1024] = {0}; int i = 0; for(i=0; i<5; ++i){ printf("client send#"); fflush(stdout); ssize_t s = read(0,buff,sizeof(buff)-1); buff[s-1] = 0; write(fd,buff,sizeof(buff)); } close(fd); return 0; }
(代碼貌似有些小問題,待修復...)
四、額外說明
對於以只讀方式(O_RDONLY)打開的FIFO文件,如果open調用是阻塞的(即第二個參數為O_RDONLY),除非有一個進程以寫方式打開同一個FIFO,否則它不會返回;
對於以只寫方式(O_WRONLY)打開的FIFO文件,如果open調用是阻塞的(即第二個參數為O_WRONLY),open調用將被阻塞,直到有一個進程以只讀方式打開同一個FIFO文件為止;
程序不能以O_RDWR模式打開FIFO文件進行讀寫操作,這樣做的後果並未明確定義,如果一個管道以讀/寫方式打開,進程就會從這個管道讀回它自己的輸出.
五、對比管道(pipe)與命名管道(fifo)
管道(pipe)用於具有血緣關系的的進程間通信,而命名管道(fifo)可以用於任意兩個進程之間通信.
簡述Linux進程間通信之命名管道FIFO