IPC - 命名管道(fifo)- 使用
Posted Redamanc
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IPC - 命名管道(fifo)- 使用相关的知识,希望对你有一定的参考价值。
命名管道
我们前面介绍了匿名管道(pipe
),匿名管道实际上就是:内存上的一块缓存。
它的主要实现方式是借助于fork
之后父进程
和子进程
会共享之前已经打开的文件描述符,并且父进程关闭fd[0]
读端,子进程关闭fd[1]
写端来实现的。
之所以说它是匿名管道,是因为,它在内核
中开辟的缓存
并没有一个名字。
那么,通过名字就能理解了,命名管道就是在内核
中开辟的缓存
有自己的名字了。
其实,这也就是命名管道和匿名管道之间的区别。
命名管道的本质和匿名管道是一样的,都是一块内存上的缓存。
但是不一样的是,命名管道在开辟缓存的同时,还会与之对应一个文件系统中的管道文件。
之后,我们通过对文件的处理(open
、read
、write
)等,就可以操作这一块缓存
了。
函数原型
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char* pathname, mode_t mode);
函数返回值:
成功 返回:0;
失败 返回:-1。
原型解读:
参数pathname
:指定想要创建的FIFO文件路径;
参数mode
:指定创建的FIFO文件访问模式(权限)。
注意事项
- 只要对FIFO有适当的访问权限,FIFO可以用在两个没有任何关系的进程之间通信。(对比
pipe
:只能使用在血缘关系的进程中:父子进程、兄弟进程); - 本质上是内核中的一块缓存,另在文件系统中以一个特殊的设备文件(管道文件)存在;
- 在文件系统中只有一个索引块存放文件的路径,没有数据块,所有的数据都存放在内核中;
- 命名管道
必须读和写同时打开
,否则单独地读和写会造成堵塞; - 可以使用命令
mkfifo
创建命名管道(内部其实还是调用了mkfifo()
函数); - 对FIFO的操作和普通文件一样;
- 一旦已经用
mkfifo
创建了一个FIFO文件,就可以用open
打开它,一般的文件I/O函数(close
、read
、write
)等都可以操作。
FIFO出错信息
- EACCES(无存取权限)
- EEXIST(指定文件不存在)
- ENAMETOOLONG(路径名太长)
- ENOENT(包含的目录不存在)
- ENOSPC(文件系统剩余空间不足)
- ENOTDIR(文件路径无效)
- EROFS(指定的文件存在于只读文件系统中)
简单应用
为了模拟两个没有任何关系
的进程,我们写两个文件:
fifo_read.c
和fifo_write.c
:
首先是从命名管道中读取数据的fifo_read.c
:
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <memory.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("usage:%s fifo\\n", argv[0]);
exit(1);
}
printf("open fifo read...\\n");
// 打开命名管道
int fd = open(argv[1], O_RDONLY);
if (fd < 0)
{
perror("open error");
exit(1);
}
else
{
printf("open fifo read success: %d\\n", fd);
}
// 从命名管道中读取数据
char buf[512];
memset(buf, 0, sizeof(buf));
while (read(fd, buf, sizeof(buf)) < 0)
{
perror("read error");
}
printf("%s\\n", buf);
close(fd);
exit(0);
}
接下来是向命名管道中写入数据的fifo_write.c
:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("usage:%s fifo\\n", argv[0]);
exit(1);
}
printf("open fifo write...\\n");
// 打开命名管道
int fd = open(argv[1], O_WRONLY);
if (fd < 0)
{
perror("open error");
exit(1);
}
else
{
printf("open fifo write success:%d\\n", fd);
}
// 写数据
char *s = "1234567890";
size_t size = strlen(s);
if(write(fd,s,size) != size)
{
perror("write error");
}
close(fd);
exit(0);
}
接下来我们通过命令行mkfifo
来创建FIFO
文件:
我们可以通过命令ls -l
来查看详细的文件信息:
可以看到该文件是一个管道文件。
接下来我们通过执行我们写的文件,需要传入管道文件的参数:
同样的,我们调用fifo_write
写文件:
这也刚好印证了我们前面说过的特性:
命名管道必须读和写同时打开
,否则单独地读和写会造成堵塞。
所以我们同时运行读
和写
:
可以看到读
和写
打开的文件描述符都是3
,并且,可以正常的读出管道中的数据。
参考资料
【1】LuckY_chh. bilibili. Linux系统程序设计–IPC. 2018-11-27
以上是关于IPC - 命名管道(fifo)- 使用的主要内容,如果未能解决你的问题,请参考以下文章