UNIX 环境编程 之 进程间通讯(IPC) 三 命名管道(FIFO)

本文介绍了命名管道(FIFO)与管道(pipe)的区别,命名管道可实现无亲缘关系进程间通讯。阐述了管道函数mkfifo的使用,以及往管道write的情况和相关变量。还说明了无亲缘关系FIFO的使用,最后总结了FIFO与管道在创建、删除及通讯方面的不同。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 概述

命名管道(FIFO) 跟管道(pipe)最大的一个区别,要让无亲缘关系的两个进程间通讯,管道是做不到的。而命名管道其实是跟路径名关联的,从而允许无亲缘关系的两个进程间通讯。

二 管道函数的使用

mkfifo函数

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

int mkfifo(const char *filename,mode_t mode);
					返回:若成功则为 0 ,若出错则为 -1

FIFO其实是一种文件类型,判断是否是FIFO类型文件,可用S_ISFIFO。
而mkfifo 可以创建该文件类型的文件。mkfifo 创建文件时隐含指定O_CREAT|O_EXCL,(不存在会创建,存在返回EEXIST错误)。因此创建文件可以用mkfifo,打开已经创建的文件则可以用open。(一般情况下先调用mkfifo,检测错误是否是EEXIST,是的话调用open即可)

注意点:以下几条特性,不管是pipe管道,还是命名管道(FIFO)都适用,下面只写了管道,其实包括了命名管道,pipe管道这两种管道。
在这里插入图片描述
正文,详细说明往管道write 情况

  • 写管道时,常熟PIPE_BUF规定了内核中管道的缓存区大小,write应要求写的字节数小于等于PIPE_BUF。这时写操作不会与其他进程的写操作穿插进行。write操作保证是原子的,一旦有个进程的写的字节大于PIPE_BUF,数据就可能会穿插进行。
  • 引入几个变量
    1.待写入的字节数 nwriteSize
    2.write返回实际写入的字节数 nreturnSize
    3.PIPE_BUF 内核中管道的缓存区大小
    4.管道中当前可用的空间大小 Left_PIPE_BUF 。
    当非阻塞模式下O_NONBLOCK ,写管道时。
    (1) nwriteSize < Left_PIPE_BUF 全部写入管道
    (2) Left_PIPE_BUF < nwriteSize < PIPE_BUF 返回EAGAIN错误。因为nwriteSize < PIPE_BUF 需要保持原子性,确保一次性写的数据是完整的。而 Left_PIPE_BUF < nwriteSize 使得数据不能全部一次性写入。阻塞情况下会等待Left_PIPE_BUF >nwriteSize 时写入,但是非阻塞模式,就会返回错误
    (3) nwriteSize > PIPE_BUF Left_PIPE_BUF有多少空间就会写入多少字节,若Left_PIPE_BUF = 0 ,返回EAGAIN 错误
  • 对于往管道write的一端并没有打开读的,返回SIGPIPE信号,要是不抓获或者不设置忽略该信号,默认终止该进程。若设置了忽略则返回EPIPE错误。

三 无亲缘关系FIFO使用

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#define FIFO1 "/tmp/fifo1"
#define FIFO2 "/tmp/fifo2"


int ipc_fifo(){
	int readfd, writefd;
	pid_t childpid;
	if(mkfifo(FIFO1,0) <0 && (errno != EEXIST)){
		return -1;
	}

	if(mkfifo(FIFO2,0) <0 && (errno != EEXIST)){
		return -1;
	}

	childpid = fork();
	if(childpid ==0){
		readfd= open(FIFO1,O_RDONLY,0);
		writefd = open(FIFO2,O_WRONLY,0);

		char buffer[128] = {0};
		read(readfd,buffer,128);
		printf("child read buffer:%s\n",buffer);

		write(writefd,"child tell parent something\n",strlen("child tell parent something\n"));

		close(readfd);
		close(writefd);

		exit(0);

	}

	writefd = open(FIFO1,O_WRONLY,0);
	readfd =  open(FIFO2,O_RDONLY,0);

	write(writefd,"parent tell child something\n",strlen("parent tell child something\n"));

	char buffer[128] = {0};
	read(readfd,buffer,128);
	printf("parent read buffer:%s\n",buffer);


	waitpid(childpid,NULL,0);
	close(readfd);
	close(writefd);
	unlink(FIFO1);
	unlink(FIFO2);
	return 1;
}

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

四 总结

通过上面例子,你可以发现跟之前的pipe管道有两个不同的点

  • 创建打开管道只需调用一次pipe,而创建打开fifo则需要调用mkfifo后再调用open。
  • 管道程序退出后也就自动消失了,而fifo的名字则需要调用unlink才从文件系统中删除。即上面的程序如果不调用unlink。你可以在tmp下找到 fifo1 ,fifo2.
  • 同时fifo跟管道比是可以在无亲缘关系的两个进程间通讯的,而上面例子没有单独写两个无关缘进程。有兴趣可以自己实现下
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值