Linux进程间通信之有名管道编程

17 篇文章 0 订阅
11 篇文章 0 订阅

无名管道虽然可以在两个进程间交换数据,但也仅限于在相关的程序之间传递数据,即这些程序是由一个共同的祖先进程启动的。但如果我们想在不相关的进程间交换数据,这还是很不方便。

我们可以用有名管道来完成这项工作。有名管道(FIFO)是一种特殊类型的文件,它在文件系统中以文件名的形式存在,但它的行为却和无名管道类似。

有名管道的创建

我们可以在命令行上创建命名管道,也可以在程序中创建它。命令行上用来创建有名管道如下所示:
mknod filename p
mkfifo filename
其中,并不是所有的UNIX系统都支持mknod命令,推荐使用mkfifo。

在程序中,我们可以使用两个不同的函数调用,如下:

#include<sys/types.h>
#include<sys/stat.h>
int mkfifo(const char *filename, mode_t mode);
int mknod(const char *filename, mode_t mode | S_IFIFO, (dev_t)0);

mknod函数可以建立许多特殊类型的文件。要想通过这个函数创建一个有名管道,唯一具有可移植性的方法是使用一个dev_t类型的值0,并将文件访问模式与S_IFIFO按位或。
下面的例子介绍mkfifo函数的简单使用:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>

int main()
{
	int res = mkfifo("my_fifo", 0777);
	if(res == 0) printf("FIFO created\n");
	exit(EXIT_SUCCESS);
}

在这里插入图片描述
这个程序用mkfifo函数创建了一个特殊的文件,虽然我们要求文件的模式是0777,但它被用户掩码设置给改变了,这与普通文件的创建是一样的,所以文件的最终模式是755。

访问FIFO文件

命令行访问

  1. 首先我们先来尝试读这个刚刚创建的FIFO文件my_fifo:
    在这里插入图片描述
    可以看到,在尝试读my_fifo时,my_fifo为空,所以该命令被阻塞挂起以等待数据出现在my_fifo中。为何阻塞而不是结束进程,在下面会介绍。
  2. 现在尝试向my_fifo写数据,当前shell被阻塞,所以必须用另一个shell来执行下面的命令:
    在这里插入图片描述
    命令执行完后将会看到cat命令产生输出。如果不向my_fifo写入任何数据,cat会一直被挂起,直到中断它。
    在这里插入图片描述
    我们也可以把cat命令放到后台执行,这样即可一次执行两个命令:
    在这里插入图片描述

程序中访问FIFO文件

与通过pipe调用创建无名管道不同,FIFO是以命名文件的形式存在,而不是打开的文件描述符,所以在对它进行读写操作之前必须打开它,FIFO也用open和close函数打开和关闭,这和对文件的操作是一样的,但它多了一些其他的功能。对FIFO来说,传递给open调用的是FIFO的路径名,而不是一个正常的文件。

使用open打开FIFO文件

打开FIFO的一个主要限制是,程序不能以O_RDWR模式打开FIFO文件进行读写操作,这样做的后果并未明确定义。但这个限制是有道理的,因为我们通常使用FIFO只是为了单向传递数据,所以没有必要使用O_RDWR模式。如果一个管道以读/写方式打开,进程就会从这个管道读回它自己的输出。
如果确实需要在程序之间双向传递数据,最好使用一对FIFO或管道, 一个方向使用一个,或者(但并不常用)采用先关闭再重新打开FIFO的方法来明确地改变数据流的方向。
打开FIFO文件和打开普通文件的另一点区别是,对open_flag (open函数的第二个参数)的O_NONBLOCK选项的用法。使用这个选项不仅改变open调用的处理方式,还会改变对这次open调用返回的文件描述符进行的读写请求的处理方式。
O_RDONLY、O_WRONLY和O_NONBLOCK标志共用以下四种组合方式:

open(const char *path, O_RDONLY);

  • 在上面这种情况下,open调用将阻塞,除非有一个进程以写方式打开同一个FIFO,否则他不会返回。这与上面介绍的cat访问FIFO的例子类似。

open(const char *path, O_RDONLY | O_NONBLOCK);

  • 加上O_NONBLOCK后,即使没有其他进程以写方式打开FIFO,这个open调用也将成功并立刻返回。

open(const char *path, O_WRONLY);

  • 在上面这种情况下,open调用将阻塞,除非有一个进程以读方式打开同一个FIFO。

open(const char *path, O_WRONLY | O_NONBLOCK);

  • 这个函数调用总是立刻返回,但如果没有进程以读方式打开FIFO文件, open调用将返回一个错误-1并且FIFO也不会被打开。如果确实有一个进程以读方式打开FIFO文件,那么我们就可以通过它返回的文件描述符对这个FIFO文件进行写操作。

请注意O_NONBLOCK分别搭配O_RDONLY和O_WRONLY在效果上的不同,如果没有进程以读方式打开管道,非阻塞写方式的open调用将失败,但非阻塞读方式的open调用总是成功。close调用的行为并不受O_NONBLOCK标志的影响。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_200_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值