fifo 文件是一种先进先出的特殊文件,即命名管道。从 man7 上可以看到 fifo 的相关信息,摘抄如下:
A FIFO special file (a named pipe) is similar to a pipe, except that it is accessed as part of the filesystem. It can be opened by multiple processes for reading or writing. When processes are exchanging data via the FIFO, the kernel passes all data internally without writing it to the filesystem. Thus, the FIFO special file has no contents on the filesystem; the filesystem entry merely serves as a reference point so that processes can access the pipe using a name in the filesystem. The kernel maintains exactly one pipe object for each FIFO special file that is opened by at least one process. The FIFO must be opened on both ends (reading and writing) before data can be passed. Normally, opening the FIFO blocks until the other end is opened also.
根据上述描述可以知道,通过 fifo 文件能够实现进程间通信。下面代码展示了进程间通信的demo。在进程间通信时,设定 client 和 server。其中,client 发送数据,server 接收数据,并且同时启动多个 client,在 server 侧观察接收到的数据是否正常。
通信过程中的结构体定义:
struct data {
char name[16];
int pid;
int num;
};
client.c 代码:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include "common.h"
const char *fifo = "/tmp/fifo";
int main(int argc, char *argv[])
{
int idx = 0;
struct data d;
int fd;
if (argc != 2) {
printf("Usage: %s prompt\n", argv[0]);
return -1;
}
fd = open(fifo, O_WRONLY);
if (fd == -1) {
perror("open fifo failed");
return -1;
}
memset(d.name, 0, 16);
strncpy(d.name, argv[1], 15);
d.pid = getpid();
printf("begin to send data ...\n");
while (idx < 100) {
d.num = idx++;
write(fd, &d, sizeof(struct data));
sleep(1);
}
return 0;
}
server.c 代码:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include "common.h"
const char *fifo = "/tmp/fifo";
int main(void)
{
int fd;
struct data d;
int ret;
fd = open(fifo, O_RDONLY);
if (fd == -1) {
perror("open fifo failed");
return -1;
}
printf("begin to receive data ...\n");
while (1) {
ret = read(fd, &d, sizeof(struct data));
if (ret < sizeof(struct data))
break;
printf("%s, %d, %d\n", d.name, d.pid, d.num);
sleep(1);
}
return 0;
}
运行效果:
1)创建 fifo 文件
$ mkfifo /tmp/fifo
2)启动第 1 个 client
$ ./client proc1
3)启动第 2 个 client
$ ./client proc2
4)启动 server
$ ./server
begin to receive data ...
proc2, 2348917, 0
proc1, 2348910, 0
proc2, 2348917, 1
proc1, 2348910, 1
proc2, 2348917, 2
proc1, 2348910, 2
proc2, 2348917, 3
proc1, 2348910, 3
...
从运行结果来看,正如上面引用中的描述那样,client 在调用 open 打开 fifo 文件时,会发生阻塞,一直到 server 也调用 open 打开 fifo 文件为止。
注意:
当打开 fifo 文件的某个进程退出时,其他打开该 fifo 文件的进程将会收到 SIGPIPE 信号,默认处理是退出当前进程,因此必要时需要对该信号进行自定义处理。
参考资料: