IPC - 命名管道(fifo)- 使用

命名管道

我们前面介绍了匿名管道pipe),匿名管道实际上就是:内存上的一块缓存
它的主要实现方式是借助于fork之后父进程子进程会共享之前已经打开的文件描述符,并且父进程关闭fd[0]读端,子进程关闭fd[1]写端来实现的。

之所以说它是匿名管道,是因为,它在内核中开辟的缓存并没有一个名字。
那么,通过名字就能理解了,命名管道就是在内核中开辟的缓存有自己的名字了。

其实,这也就是命名管道和匿名管道之间的区别。
命名管道的本质和匿名管道是一样的,都是一块内存上的缓存
但是不一样的是,命名管道在开辟缓存的同时,还会与之对应一个文件系统中的管道文件
之后,我们通过对文件的处理(openreadwrite)等,就可以操作这一块缓存了。

函数原型

#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函数closereadwrite)等都可以操作。

FIFO出错信息

  • EACCES(无存取权限)
  • EEXIST(指定文件不存在)
  • ENAMETOOLONG(路径名太长)
  • ENOENT(包含的目录不存在)
  • ENOSPC(文件系统剩余空间不足)
  • ENOTDIR(文件路径无效)
  • EROFS(指定的文件存在于只读文件系统中)

简单应用

为了模拟两个没有任何关系的进程,我们写两个文件:
fifo_read.cfifo_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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值