引入

pipe最大的劣势就是只能用于有共同祖先的各个进程之间,无法在没有亲缘关系的两个进程间创建一个管道并将它用作IPC通道。FIFO解决了这一点,它通过文件系统中的路径名作为名字来指定访问的进程。

命名管道FIFO、创建mkfifo

匿名管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。
如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。
FIFO文件在磁盘上没有数据块,仅用来标识内核中的一条通道。文件类型标识为p表示FIFO,文件大小为0。

我们可以通过命令行创建:
$ mkfifo filename
在这里插入图片描述
FIFO是一种文件类型,所以创建FIFO类似于创建一个文件。
我们也可以通过函数创建,就是mkfifo函数

NAME
       mkfifo, mkfifoat - make a FIFO special file (a named pipe)

SYNOPSIS
       #include <sys/types.h>
       #include <sys/stat.h>

       int mkfifo(const char *pathname, mode_t mode);

       #include <fcntl.h>           /* Definition of AT_* constants */
       #include <sys/stat.h>

       int mkfifoat(int dirfd, const char *pathname, mode_t mode);

RETURN VALUE
       On success mkfifo() and mkfifoat() return 0.  In the case of an error, -1 is returned (in which case, errno is set appropriately).

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *filename,mode_t mode);
参数1为绝对路径字符串,参数2为指定文件权限位,即三位数字,或使用定义在#include <sys/stat.h>中的常值
返回:成功返回0,出错为-1
mkfifo函数已经隐含指定O_CREAT|O_EXCL(类似open函数)。也就是说,它要么创建一个新的FIFO,要么返回一个EEXIST错误。解决这一问题也很简单,只要在mkfifo之前用access函数判断文件是否已经存在就好了。
读端代码示例:

#include <iostream>
#include<unistd.h>//unix stand lib
#include<sys/types.h>
#include<sys/fcntl.h>
#include<sys/stat.h>
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<dirent.h>//file dir
#include <sys/wait.h>//wait func
#include <stdlib.h>//ststem
#include <signal.h>
#include <string.h>

using namespace std;

#define FIFO1 "/tmp/teacher.fifo"
//=============================================读端====================
int main(int argc, char *argv[])
{
	int fifo_fd;
	
	char buffer[50];
	bzero(buffer, sizeof(buffer));
	int r_size = 0;
	
	//access检查是否已经有这个文件,使得已经创建文件时不报错
	if (access("/tmp/teacher.fifo", F_OK) == -1)///tmp/teacher.fifo文件不存在再创建
	{
		if (mkfifo("/tmp/teacher.fifo", 0664) == -1)
		{
			perror("mkfifo create:");
			return -1;
		}	
	}

	//它是个文件,肯定要打开它,所以要定义文件描述符
	fifo_fd = open("/tmp/teacher.fifo", O_RDONLY);//O_RDONLY只读
	if (fifo_fd == -1)
	{
		perror("fifo_fd  open error:");
		return -1;
	}
	cout << "read " << endl;
	
	r_size=read(fifo_fd, buffer, sizeof(buffer));//接收前strlen==0,所以必须用sizeof
	cout << "receive buffer= " << buffer << endl;
	while (1)
	{
		sleep(1);
	}
	return 0;
}

运行结果:
在这里插入图片描述

说明:

  • FIFO文件也要用open和close函数来打开或关闭
  • 传递给open调用的是一个FIFO文件的路径名,而不是一个正常文件的路径名
  • 一个FIFO不能打开又读又写,也就是说open时模式参数不能为O_RDWR。
  • 如果确实需要在程序之间双向传递数据的话,我们可以同时使用一对FIFO或管道,一个方向配一个;还可以用先关闭再重新打开FIFO的办法明确地改变数据流的方向

FIFO读写规则

为读而打开FIFO时
O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO(上例)
O_NONBLOCK enable:立刻返回成功
为写而打开FIFO时
O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO
O_NONBLOCK enable:立刻返回失败,错误码为ENXIO

需要注意的是 命名管道与匿名管道的读写规则是一样的,参见上一篇

FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,这些工作完成之后,它们具有相同的语义。

The only difference between pipes and FIFOs is the manner in which
they are created and opened. Once these tasks have been accomplished,
I/O on pipes and FIFOs has exactly the same semantics.

Logo

更多推荐