linux进程通信之命名管道

本文详细介绍了Linux中的命名管道(FIFO)通信方式,它是一种允许不相关进程间通信的机制,与无名管道相比,命名管道通过路径名关联并在文件系统中存在。通过mkfifo函数创建FIFO,并且可以使用open、read、write等系统调用进行操作。文章列举了打开FIFO的四种模式,并强调了阻塞和非阻塞模式下的行为。最后,提供了一个示例展示了如何使用命名管道实现多进程间的通信。

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

前一节学习了无名管道,这节学习命名管道。

二命名管道
无名管道只能用来在父子进程或兄弟进程之间进行通信,这就给没有亲缘关系的进程之间数据的交换带来了麻烦,解决这个问题就是本节要学习的另一种管道通信:命名管道。
命名管道也被称为FIFO文件,FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。值得注意的是,FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。

http://blog.csdn.net/xiaoliangsky/article/details/40121893

1 mkfifo
int mkfifo(const char *pathname, mode_t mode);
mafifo函数创建一个FIFO,FIFO在文件系统中表现为一个文件。
pahtname 文件路径
mode 和系统调用open函数中的mode是一样的。

返回值
如果函数调用成功返回非-1;
函数调用失败返回-1。

2 命名管道操作
FIFO在文件系统中表现为一个文件,大部分的系统文件调用都可以用在FIFO上面,比如:read,open,write,close,unlink,stat等函数。但是seek等函数不能对FIFO调用。

2.1 打开命名管道
可以调用open函数打开命名管道,但是有两点要注意
1)不能以O_RDWR模式打开命名管道FIFO文件,否则其行为是未定义的,管道是单向的,不能同时读写;
2)就是传递给open调用的是FIFO的路径名,而不是正常的文件

打开FIFO文件通常有四种方式:
open(pathname, O_RDONLY);//1只读、阻塞模式
open(pathname, O_RDONLY | O_NONBLOCK);//2只读、非阻塞模式
open(pathname, O_WRONLY);//3只写、阻塞模式
open(pathname, O_WRONLY | O_NONBLOCK);//只写、非阻塞模式

注意阻塞模式open打开FIFO:
1)当以阻塞、只读模式打开FIFO文件时,将会阻塞,直到其他进程以写方式打开访问文件;
2)当以阻塞、只写模式打开FIFO文件时,将会阻塞,直到其他进程以读方式打开文件;
3)当以非阻塞方式(指定O_NONBLOCK)方式只读打开FIFO的时候,则立即返回。当只写open时,如果没有进程为读打开FIFO,则返回-1,其errno是ENXIO。
下面是一个命名管道的例子:

用命名管道实现多个进程间的通信,一个server进程负责接受多个cilent进程发来的消息

server.c代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/stat.h>

typedef struct 
{
	pid_t     child_pid;
	char      message[PIPE_BUF+1];
}fifo_message;

int main()
{
	int                     fd;
	const char             *fifoname;
	fifo_message            msgbuf;

	fifoname = "/tmp/serverfifo";

	if (access(fifoname, F_OK) == -1)
	{
		if (mkfifo(fifoname, 0666) == -1)
		{
			perror("mkfifo error\n");
			exit(-1);
		}
	}

	if ((fd = open(fifoname, O_RDONLY)) == -1)//以只读、阻塞模式打开
	{
		fprintf(stdout, "open %s failed\n", fifoname);
		exit(-1);
	}

	while (1)
	{
		if (read(fd, &msgbuf, sizeof(msgbuf)) < 0)
		{
			close(fd);
			perror("read error\n");
			exit(-1);
		}

		fprintf(stdout, "message from child: %d, message: %s\n", msgbuf.child_pid, msgbuf.message);
		sleep(1);
	}
    
	return 0;
}

client.c的代码:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

struct fifo_message
{
	pid_t      child_pid;
	char       message[PIPE_BUF+1];
};


int main()
{
	int                     fd;
	const char             *fifoname;
	struct fifo_message     msgbuf;

	fifoname = "/tmp/serverfifo";
	if (access(fifoname, F_OK) == -1)
	{
		perror("access error\n");
		exit(-1);
	}

	if ((fd = open(fifoname, O_WRONLY)) < 0)//以只写、阻塞模式打开
	{
		perror("open error\n");
	}

	msgbuf.child_pid = getpid();

	while (1)
	{
		printf("input the message: ");
		if (fgets(msgbuf.message, sizeof(msgbuf.message), stdin) == NULL)
		{
			perror("fgets error or end\n");
			break;
		}

		msgbuf.message[strlen(msgbuf.message)] = '\0';

		if (write(fd, &msgbuf, sizeof(msgbuf)) == -1)
		{
			perror("write error\n");
			close(fd);
			exit(-1);
		}
	}
	
	close(fd);

	return 0;
}

运行结果:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值