一、命名管道(FIFO)
FIFO也被称为命名管道,是一种文件类型。匿名管道(pipe)只能在具有亲缘关系间的进程使用。但是,通过FIFO,不相关的进程也能交换数据。
FIFO(First Input First Output)是一种传统的按序执行方法,对管道及FIFO读总是从起始位置返回数据,对它们的写则把数据添加到末尾
二、命名管道函数
2.1 mkfifo函数
/*
功能:创建一个FIFO管道文件,用于提供FIFO功能
参数:
pathname:文件名或路径名,用于在文件系统中创建一个专用文件
mode:用于规定FIFO文件权限,与open函数中mode一致。一旦创建了FIFO文件,就可以用一般的文件I/O函数操作它
返回值:成功返回 0,失败返回 -1
*/
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
实际上,当我们调用mkfifo创建一个FIFO命名管道的时候,内核会为这个FIFO(伪)文件创建一个缓存区,当我们对FIFO文件进行open,read,write等文件I/O操作的时候就相当于操作这个缓存区,以此来实现进程间通信。
2.2 open函数
/*
功能:打开或创建文件,在打开或创建文件时可以制定文件的属性及用户的权限等各种参数。
参数:
pathname:文件名或路径名。文件为当前目录下文件,路径名则为绝对路径名(如:/usr/local/mysql)
oflages:打开的文件权限
mode:设置文件访问权限的初始值
返回值:成功返回指向文件的文件描述符,失败返回 -1
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
注:第三个参数是在第二个参数中有O_CREAT时才用作用。若没有,则第三个参数可以忽略。
三、编程示例:
3.1 编程目的:使用FIFO管道,实现两个无亲缘关系进程间的数据通信
3.2 编程思路:FIFO管道是一种半双工的通信方式,在同一时刻只能有一种数据流向,为实现数据双向流通,我们可以创建两条管道。管道0:A进程为读端,B进程为写端;管道1:A进程为写端,B进程为读端。
3.3 代码展示:
创建管道部分代码:
//创建两个进程,输入0或1分别对应管道读写权限
if(argc != 2)
{
printf("error! please choice one FIFO_FILE\n");
return 0;
}
mode=atoi(argv[1]);
printf("mode:%d\n",mode);
//在创建管道前先使用access函数确认函数是否存在
if(access(FIFO_FILE0,F_OK) < 0)
{
printf("file not exist");
mkfifo(FIFO_FILE0,0666);
}
if(access(FIFO_FILE1,F_OK) < 0)
{
printf("file not exist");
mkfifo(FIFO_FILE1,0666);
}
// 进程0:作为管道FIFO_FILE0的读端,FIFO_FILE1的写端
// 注:这里以只读模式打开命名管道FIFO_FILE0的读端,默认是阻塞模式;如果命名管道的写端不被打开则open()将会一直阻塞,所以另外一个进程必须首先以写模式打开该文件FIFO_FILE0,否则会出现死锁
if(mode == 0)
{
if((read_fd=open(FIFO_FILE0,O_RDONLY)) < 0)
{
printf("open FIFO_FILE0 failure:%s\n",strerror(errno));
return 0;
}
if((write_fd=open(FIFO_FILE1,O_WRONLY)) < 0)
{
printf("open FIFO_FILE1 failure:%s\n",strerror(errno));
return 0;
}
}
// 进程1:作为管道FIFO_FILE0的写端,FIFO_FILE1的读端
// 注:这里以只写模式打开命名管道FIFO_FILE0的写端,默认是阻塞模式;如果命名管道的读端不被打开则open()将会一直阻塞,所以另外一个进程必须首先以读模式打开该文件FIFO_FILE0,否则会出现死锁
if(mode == 1)
{
if((write_fd=open(FIFO_FILE0,O_WRONLY)) < 0)
{
printf("open FIFO_FILE0 failure:%s\n",strerror(errno));
return 0;
}
if((read_fd=open(FIFO_FILE1,O_RDONLY)) < 0)
{
printf("open FIFO_FILE1 failure:%s\n",strerror(errno));
return 0;
}
}
//管道FIFO_FILE0:进程1写入数据,进程0读取数据;
//管道FIFO_FILE1:进程0写入数据,进程1读取数据;
以上为命名管道FIFO创建部分代码,可使用open函数返回的read_fd、write_fd向管道缓存区读取或写入数据,这里就不给大家演示了。