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)可以用于任意两个进程之间通信.