如果我们要在不相关的进程间交换数据,那么使用FIFO文件将会十分方便。
FIFO文件通常也称为命名管道(named pipe)。命名管道是一种特殊类型的文件,它在文件系统中以文件名的形式存在。
创建命名管道一般有两种方式:
一个比较旧的方式是:
mknod filename p
这个命令并未出现在X/Open规范的命令列表中,所以可能并不是所有的类Unix系统都可以这样做。
推荐的做法是:
mkfifo filename
#include
#include
int mkfifo(const char *pathname, mode_t mode);
int mknod(const char *pathname, mode_t mode | S_FIFO, (dev_t)0);
函数说明
下面代码演示了mkfifo函数的用法:
#include
#include
#include
#include
#include
int main()
{
int res = mkfifo("~/Test/PipeTest/my_fifo",0777);
if(!res)
printf("FIFO created\n");
exit(EXIT_SUCCESS);
}
运行结果:
linux中ls命令的-F选项是列出文件的类型。
同样有两种方式访问FIFO文件。
首先用cat命令读取刚才创建的FIFO文件:
cat < /tmp/my_fifo
这个时候,cat命令将一直挂起,直到终端或者有数据发送到FIFO中。
然后尝试向FIFO中写数据(在另外一个终端执行这个命令)
echo "FIFO test" > /tmp/my_fifo
这个时候cat将会输出内容。
首先需要注意的是:
与通过pipe调用创建管道不同,FIFO是以命名文件的形式存在,而不是打开的文件描述符,所以在对它进行读写操作之前必须先打开它。
1、使用open函数打开FIFO文件
#include
#include
#include
int open(const char *pathname, int flags);
第一个是不能以O_RDWR模式打开FIFO文件进行读写操作。这样做的行为是未定义的。
因为我们通常使用FIFO只是为了单向传递数据,所以没有必要使用这个模式。
如果确实需要在程序之间双向传递数据,最好使用一对FIFO或管道,一个方向使用一个。或者采用先关闭在重新打开FIFO的方法来明确改变数据流的方向。
第二是对标志位的O_NONBLOCK选项的用法。
使用这个选项不仅改变open调用的处理方式,还会改变对这次open调用返回的文件描述符进行的读写请求的处理方式。
O_RDONLY、O_WRONLY和O_NONBLOCK标志共有四种合法的组合方式:
测试代码:
#include
#include
#include
#include
#include
#include
#include
#define FIFO_NAME "/tmp/my_fifo"
int main(int argc,char *argv[])
{
int res,i;
int open_mode=0;
if(argc < 2){
fprintf(stderr,"Usage:%s
open函数调用中的参数标志O_NONBLOCK会影响FIFO的读写操作。
规则如下:
其中。PIPE_BUF是FIFO的长度,它在头文件limits.h中被定义。在linux或其他类UNIX系统中,它的值通常是4096字节。
在这里需要注意的是:
有两个进程去访问FIFO管道时,Linux会安排好两个进程之间的调度,使得两个进程在可以运行的时候运行,在不能运行的时候阻塞。
下面的程序用命名管道在两个独立的进程之间通信,模拟了消费者和生产者程序。
生产者程序fork3.c:
//生产者程序
#include
#include
#include
#include
#include
#include
#include
#include
#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF
#define TEN_MSG (1024 * 1024 * 10)
int main()
{
int pipe_fd;
int res;
int open_mode = O_WRONLY;
int bytes_sent = 0;
char buffer[BUFFER_SIZE + 1];
printf("Productor Program beginning...\n");
//检查FIFO文件是否存在
if(access(FIFO_NAME, F_OK) == -1){
res = mkfifo(FIFO_NAME, 0777);
if(res != 0){
fprintf(stderr, "Could not create fifo %s\n", FIFO_NAME);
exit(EXIT_FAILURE);
}
}
printf("Process %d opening FIFO O_WRONLY\n", getpid());
//打开FIFO文件
pipe_fd = open(FIFO_NAME, open_mode);
printf("Process %d result %d\n", getpid(), pipe_fd);
if(pipe_fd != -1){
while(bytes_sent < TEN_MSG){
res = write(pipe_fd, buffer, BUFFER_SIZE); //向FIFO写入数据
if(res == -1){
fprintf(stderr, "Write error on pipe\n");
exit(EXIT_FAILURE);
}
bytes_sent += res;
}
(void)close(pipe_fd);
}
else{
exit(EXIT_FAILURE);
}
printf("Process %d finished\n", getpid());
exit(EXIT_SUCCESS);
}
//消费者程序
#include
#include
#include
#include
#include
#include
#include
#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF
int main()
{
int pipe_fd;
int res;
int open_mode = O_RDONLY;
char buffer[BUFFER_SIZE + 1];
int bytes = 0;
printf("COnsumer Program beginning...");
memset(buffer,'\0', sizeof(buffer));
printf("Process %d opeining FIFO O_RDONLY\n", getpid());
pipe_fd = open(FIFO_NAME, open_mode);
printf("Process %d result %d\n", getpid(), pipe_fd);
if (pipe_fd != -1)
{
do{
res = read(pipe_fd, buffer, BUFFER_SIZE);
bytes += res;
}while(res > 0);
close(pipe_fd);
}
else
{
exit(EXIT_FAILURE);
}
printf("Process %d finished, %d bytes read\n", getpid(), bytes);
exit(EXIT_SUCCESS);
}
可以发现读进程只运行了不到0.1S的时间,却读取了10MB的数据。这说明管道在程序之间传递数据是很有效率的。
FIFO文件使用完毕之后需删除,以免造成垃圾文件。
#include
int unlink(const char *pathname);
unlink(2) - Linux man page
如需转载,请注明出处:http://blog.csdn.net/xiajun07061225/article/details/8471777