Linux 进程间通信之 PIPE 与 FIFO

本文详细介绍了进程间通信(IPC)的两种方式:匿名管道和有名管道。首先,阐述了IPC的基本概念,接着深入讨论了匿名管道的原理、局限性、创建及读写操作,通过实例展示了如何利用匿名管道实现`ps aux | grep bash`命令。然后,讲解了有名管道(FIFO)的特性、创建方法以及应用场景,并给出了使用有名管道实现两个进程通信的示例。这些内容有助于理解不同进程间如何进行有效通信。
摘要由CSDN通过智能技术生成

目录

1. IPC

1.1 IPC 概念

1.2 进程间通信常用的几种方式

2. 匿名管道(PIPE)

2.1 管道的概念

2.2 管道的局限性

2.3 创建匿名管道

2.4 管道的读写

2.4.1 读操作

2.4.2 写操作

2.5 父子进程使用管道通信

2.5.1 实现 ps aux| grep "bash"

2.5.2 运行结果

3. 有名管道 (FIFO)

3.1 函数原型

3.2 特点

3.3 使用场景

3.4 fifo 文件可以使用 io 函数进程操作

3.5 fifo 案例实现两进程通信


1. IPC

1.1 IPC 概念

Inter Process Communication  进程间通信。

1.2 进程间通信常用的几种方式

  • 1,管道通信:有名管道,无名管道
  • 2,信号 - 系统开销小
  • 3,消息队列 - 内核的链表
  • 4,信号量 - 计数器
  • 5,共享内存
  • 6,内存映射
  • 7,套接字

2. 匿名管道(PIPE)

2.1 管道的概念

 本质:

  • 内核缓冲区
  • 伪文件-不占用磁盘空间

特点:

  • 读端,写端,对应两个文件描述符  fd[0]、fd[1]
  • 数据写端流入,读端流出
  • 操作管理的进程被销毁之后,管道自动被释放
  • 管道默认是阻塞的

2.2 管道的局限性

队列:数据只能读取一次,不能重复读取

半双工:读端操作的时候写端不能操作,写端操作的时候读端不能操作。

2.3 创建匿名管道

int pipe(int fd[2])

fd ‐ 传出参数:
           fd[0] ‐ 读端
           fd[1] ‐ 写端
 返回值:
             0:成功
            ‐1:创建失败

2.4 管道的读写

2.4.1 读操作

  • 有数据:read(fd[1])  正常读,返回读出的字节数
  • 无数据:写端被全部关闭:read 返回0,相当于读文件到了尾部。没有全部关闭:read 阻塞

2.4.2 写操作

  • 读端全部关闭:管道破裂,进程被终止。内核给当前进程发送信号SIGPIPE-13,默认处理动作
  • 读端没全部关闭:缓冲区写满了:write阻塞。缓冲区没满:write继续写,直到写满,阻塞

2.5 父子进程使用管道通信

2.5.1 实现 ps aux| grep "bash"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
	int ret;
	int fd[2];
	ret = pipe(fd); // 创建匿名管道
	if (ret == -1)
	{
		printf("create pipe failed!~\n");
		exit(1);
	}

	pid_t pid = fork(); // 创建父子进程
	if (pid == -1)
	{
		printf("fork failed!~");
		exit(1);
	}
	// 父进程 执行 ps aux
	if (pid > 0)
	{
		close(fd[0]);				// 操作写端要先关闭读端
		dup2(fd[1], STDOUT_FILENO); // 把原本输出在 STDOUT 的内容重定向至管道写端
		execlp("ps", "ps", "aux", NULL);
		perror("execlp");
		exit(1);
	}
	// 子进程 执行 grep "bash"
	else if (pid == 0)
	{
		close(fd[1]);			   // 操作读端要先关闭写端
		dup2(fd[0], STDIN_FILENO); // 把原本输出在 STDIN 的内容重定向至管道读端
		execlp("grep", "grep", "bash", "--color=auto", NULL);
		perror("execlp");
	}

	close(fd[0]);
	close(fd[1]);
	return 0;
}

2.5.2 运行结果

 程序运行结果和在终端直接写入 ps aux | grep bash 的效果一致。

3. 有名管道 (FIFO)

3.1 函数原型

int mkfifo(const char *filename,mode_t mode);
  • 功能:创建管道文件
  • 参数:管道文件文件名,权限,创建的文件权限仍然和umask有关系。
  • 返回值:创建成功返回0,创建失败返回-1。

3.2 特点

  • 在磁盘上有这样一个文件 ls -l ->p
  • 也是一个伪文件,在磁盘大小永久为0
  • 数据存在内核中有一个对应的缓冲区
  • 半双工通信方式

3.3 使用场景

  • 没有血缘关系的进程间通信

3.4 fifo 文件可以使用 io 函数进程操作

  • open/close
  • read/write
  • 不能执行 lseek 操作

3.5 fifo 案例实现两进程通信

mkfifo.c

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

int main()
{
	int ret;
	int fd;
	int nread;
	char readBuf[50] = {0};
	ret = mkfifo("/home/outside/03_IPC/myfifo", 0777); // 创建 fifo
	if (ret == -1)
	{
		perror("mkfifo");
		return -1;
	}
	else
	{
		printf("creat fifo succeed!~\n");
	}

	fd = open("./myfifo", O_RDONLY); // 打开 fifo
	if (fd < 0)
	{
		perror("fd");
		return -1;
	}
	else
	{
		printf("open fifo succeed!~\n");
	}
	nread = read(fd, readBuf, sizeof(readBuf)); // 读取 fd 的内容到 readBuf 内
	printf("read %d byte from fifo %s:\n", nread, readBuf);
	close(fd);
	return 0;
}

write.c

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

int main()
{
	char *str = "Hello World!~";
	int fd;
	fd = open("./myfifo", O_WRONLY);
	if (fd < 0)
	{
		perror("fd");
		return -1;
	}
	else
	{
		printf("open fifo succeed!~\n");
	}

	write(fd, str, strlen(str)); // 把 str 指向的字符串写入 fd 内
	close(fd);
	return 0;
}

程序运行结果:

 实现 fifo 的创建与两进程间通信。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值