Linux进程间通信-FIFO命名管道

Linux进程间通信-FIFO命名管道

1、概述

  管道因为没有名称,所以只用于进程间的亲缘通信。为了克服这一缺点,提出了命名管道(FIFO),又称命名管道、FIFO文件。

  FIFO不同于无名管道,它提供与之关联的路径名,该路径名以FIFO文件的形式存在于文件系统中。这样,即使进程与FIFO的创建进程没有亲属关系,只要能够访问路径,就可以通过FIFO相互通信。不相关的过程也可以通过FIFO交换数据。

  FIFO 在文件系统中作为一个特殊的文件而存在。虽然FIFO文件存放在文件系统中,但是FIFO 中的内容却存放在内存中。当使用 FIFO 的进程退出后,FIFO 文件将继续保存在文件系统中以便以后使用。

2、相关函数

  一旦创建了一个FIFO,就可用open打开它,一般的文件访问函数(close、read、write等)都可用于FIFO。

  FIFO在使用的过程中常用到如下函数

函数释意
mkfifo创建管道
open打开管道
read读管道
write写管道
unlink关闭管道
unlink删除管道

  上述函数中除了mkfifo函数需要注意一下,其他的函数全是标准的IO操作接口,这里不做解释。使用fifo之前需要使用mkfifo创建一个管道,同时会在指定位置创建一个用于描述管道的文件。

#include <sys/types.h>
#include <sys/stat.h>
/*
pathname:FIFO文件名
mode:属性(见文件操作章节)
返回值:若成功则返回0,否则返回-1,错误原因存于errno中。
错误代码:  
EACCESS 参数pathname所指定的目录路径无可执行的权限  
EEXIST 参数pathname所指定的文件已存在。  
ENAMETOOLONG 参数pathname的路径名称太长。  
ENOENT 参数pathname包含的目录不存在  
ENOSPC 文件系统的剩余空间不足  
ENOTDIR 参数pathname路径中的目录存在但却非真正的目录。  
EROFS 参数pathname指定的文件存在于只读文件系统内。
*/
int mkfifo(const char * pathname, mode_tmode)

  打开管道时,默认是阻塞模式,写管道时如果没有其他进程读管道写管道就会阻塞住。同理,读管道操作也是如此,如果没有进程写管道,读管道就会被阻塞住。打开管道时以O_NONBLOCK的标志打开fifo文件,程序会直接返回,不管fifo的对端是什么状态。

3、例程

  写入测试程序,先判断FIFO文件是否存在,如果文件不存在则调用mkfifo创建一个FIFO通道。以OPEN打开FIFO通道,调用fgets获取控制台输入的内容,使用write方法将数据写入到FIFO通道。

#include <errno.h>
#include <stdlib.h> //for exit
#include <stdio.h> //for printf
#include <unistd.h> //for close
#include <sys/stat.h> //for mkfifo
#include <fcntl.h> //for open
#define FIFO_NUM1 "/tmp/fifotest"
#define MAX_BUFFER_SIZE 100
int main(int argc, char * argv[])
{
	/* 判断有名管道是否已存在,若尚未创建,则以相应的权限创建 */
	if (access(FIFO_NUM1, F_OK) == -1)
	{
		if ((mkfifo(FIFO_NUM1, 0777) < 0) && (errno != EEXIST))
		{
			printf("Failed to create fifo file\n");
			exit(1);
		}
	}
	/* 以只写阻塞方式打开FIFO管道 */
	int fd = open(FIFO_NUM1, O_WRONLY);
	if (fd == -1)
	{
		printf("Failed to open fifo\n");
		exit(1);
	}
	while(1)
	{
		char buff[MAX_BUFFER_SIZE] = {0};
		fgets(buff,sizeof(buff),stdin);
		/* 向管道中写入字符串 */
		if (write(fd, buff, MAX_BUFFER_SIZE) > 0)
		{
			printf("Write '%s' to FIFO\n", buff);
		}
	}
	close(fd);
	exit(0);
}

  读取测试程序,同样先判断FIFO文件是否存在,不存在则调用mkfifo创建一个FIFO通道。使用read循环读取FIFO的内容并打印出来。

#include <errno.h>
#include <stdlib.h> //for exit
#include <stdio.h> //for printf
#include <unistd.h> //for close
#include <sys/stat.h> //for mkfifo
#include <fcntl.h> //for open
#define FIFO_NUM1 "/tmp/fifotest"
#define MAX_BUFFER_SIZE 100
int main(void)
{
	/* 判断有名管道是否已存在,若尚未创建,则以相应的权限创建 */
	if (access(FIFO_NUM1, F_OK) == -1)
	{
		if ((mkfifo(FIFO_NUM1, 0777) < 0) && (errno != EEXIST))
		{
			printf("Failed to create fifo file\n");
			exit(1);
		}
	}
	/* 以只读阻塞方式打开有名管道 */
	int fd = open(FIFO_NUM1, O_RDONLY);
	if (fd == -1)
	{
		printf("Failed to open fifo\n");
		exit(1);
	}
	while (1)
	{
		char buff[MAX_BUFFER_SIZE] = {0};
		if (read(fd, buff, MAX_BUFFER_SIZE) > 0)
		{
			printf("Read '%s' from fifo\n", buff);
		}
	}
	close(fd);
	exit(0);
}

  使用gcc分别编译文件,然后直接调用就可以运行了。可以看到运行结果与预期一致。

$ gcc ./write.c -o write
$ ./write 
11
Write '11
' to FIFO
222
Write '222
' to FIFO
333
Write '333
' to FIFO
444
Write '444
' to FIFO
$ gcc ./read.c -o read
$ ./read
Read '11
' from fifo
Read '222
' from fifo
Read '333
' from fifo
Read '444
' from fifo

4、题外话

  FIFO管道在创建时,会锁定文件的权限。我上面写的例程,创建FIFO时写入的是0777的权限,实际生成的FIFO文件却是755的权限。也就是说,FIFO文件只有创建者有权限读写,其他成员只能读取,不能执行写入的动作。

$ ls -l /tmp/fifotest 
prwxr-xr-x 1 zac zac 0 Nov 18 16:40 /tmp/fifotest

  如果有两个应用之间通过FIFO通信,但两个应用属于不同的用户。这时候读取进程按照上面所说的例程方式,先启动创建了FIFO文件。那么等写入进程运行起来后,将无法进行FIFO管道的写入操作。

  这时候读取进程需要做出一些小修改。可以每隔一段时间查询一下FIFO文件的状态,等待写入进程成功创建FIFO文件。

	xxxxxx
	/* 判断有名管道是否已存在,若尚未创建,则等待片刻*/
	while(access(FIFO_NUM1, F_OK) == -1)
	{
		usleep(200*1000);
	}
	xxxxxx

5、总结

  • 要创建和打开管道,只需调用pipe。创建和打开一个FIFO,在调用mkfifo后还需要使用open;
  • 管道在所有进程最终关闭后自动消失,只有通过调用unlink才能从文件系统中删除FIFO名称。
  • 创建FIFO文件时会锁定文件的写入权限,只有创建者才有资格写入
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

遇雪长安

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

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

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

打赏作者

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

抵扣说明:

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

余额充值