命名管道-FIFO
FIFO介绍
FIFO常被称为命名管道,以和匿名管道pipe进行区分。匿名管道pipe只能用于“有血缘关系”的进程间通信。但通过命名管道FIFO不相关的进程也能交换数据。
FIFO是Linux基础文件类型中的一种(文件类型为p,可通过 ls -l
查看文件类型)。但FIFO文件在磁盘上没有数据块,文件大小为0,仅仅用来标识内核中一条通道。进程可以打开这个文件进行read/write,实际上是在读写内核缓冲区,这样就实现了进程间通信。
创建管道
方式1 使用命令 mkfifo
命令格式:
mkfifo 管道名
,例如:mkfifo myfifo
方式2 使用函数
cpp#include <sys/types.h> #include <sys/stat.h> int mkfifo(const char* pathname, mode_t mode);
参数说明和返回值可以查看
man 3 mkfifo
当创建了一个FIFO,就可以使用open函数打开它,常见的文件I/O函数都可用于FIFO。如:close、read、write、unlink等。
FIFO严格遵循先进先出(first in first out),对FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()
等文件定位操作。
使用FIFO完成两个进程通信
- 使用FIFO完成两个进程通信的示意图
思路
进程A
- 创建一个fifo文件:myfifo
- 调用open函数打开myfifo文件
- 调用write函数写入一个字符串如:“hello world”(其实是将数据写入到了内核缓冲区)
- 调用close函数关闭myfifo文件
进程B
- 调用open函数打开myfifo文件
- 调用read函数读取文件内容(其实就是从内核中读取数据)
- 打印显示读取的内容
- 调用close函数关闭myfifo文件
注意
myfifo文件是在进程A中创建的,如果先启动进程B会报错。思考一下如何解决这个问题呢???
根据 open 函数的特性,打开失败会返回
-1
,给进程 B 添加异常处理来处理,当 open 的返回值不为-1
的时间再继续运行程序就可以了。
代码实现
processA.c
c
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int ret = mkfifo("fifo", 0744);
ret = open("fifo", O_WRONLY);
write(ret, "hello b", 8);
close(ret);
return 0;
}
processB.c
c
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int fd;
while (1)
{
fd = open("fifo", O_RDONLY);
if (fd != -1)
break;
}
char buf[1024] = {0};
read(fd, buf, sizeof(buf));
puts(buf);
close(fd);
// execlp("rm", "rm", "fifo", NULL);
unlink("fifo");
return 0;
}
稍微有点的相关函数
cpp
int mkfifo(const char *pathname, mode_t mode); // 创建有名管道
int unlink(const char *pathname); // 删除文件
int rename(const char *oldpath, const char *newpath); // 类似于linux系统命令mv
int link(const char *oldpath, const char *newpath); // 建立硬链接
管道的缺陷
任意通信的两方都要建立管道,如果需要通信的进程有很多那么就需要建立很多管道。