进程间通信之管道(匿名管道与命名管道)

news2025/1/11 20:04:54

进程间通信之管道

  • 进程间通信
    • 管道
      • 什么是管道
    • 管道分类——1.匿名管道
      • 匿名管道举例
      • 管道的特点
    • 管道分类——2.命名管道
      • 创建一个命名管道
      • 举例
      • 命名管道的打开规则
      • 匿名管道与命名管道的区别
    • 具体使用举例:
      • 例子1-用命名管道实现文件拷贝
      • 例子2-用命名管道实现server&client通信

在这里插入图片描述

📌————本章重点————📌
🔗了解什么是管道
🔗会基本使用匿名管道
🔗会基本使用命名管道
🔗了解进程间通信
🔗了解管道具体使用场景
✨————————————✨

进程间通信

首先我们先提出一个问题:进程之间为什么无法直接通信,而需要操作系统提供通信方式:
经过我们上一个博客学习我们可以知道,每个进程都有独立的虚拟地址空间,一个进程在访问一个数据的时候都是通过地址来进行访问的,进过页表映射在之后访问物理内存,因此如果想要给另一个进程传递一个数据,就要把它的地址空间传递给其他进程,因为a进程的是虚拟地址,所以b进程经过页表映射也访问不了。(这个设计的初衷是:独立虚拟空间可以更稳定)

操作系统提供进程间通信方式,就是给多个需要通信的进程之间建立起一个关联:能够共同访问的一块内存,但是因为具体通信场景不同,因此有提供不同的几种方式:管道,共享内存,消息队列,信号量口

管道

在这里插入图片描述

什么是管道

艺术来源于生活,消息传输的时候我们就流水一样,所以我们联想到了管道,因此他也有个特殊的性质半双工通信,也就是只能单向传递,同一时间不能既发送又接收管道是Unix中最古老的进程间通信的形式。我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”。
在这里插入图片描述
==这里我们可以看到,管道就是由操作系统管理,在内核中的一个缓冲区(内存)==所以多个进程访问同一块空间的时候就完成了通信

分类:

  1. 匿名管道:管道没有标识符,不能被其他进程找到,因此只能用于具有亲缘关系的进程间通信
  2. 命名管道:管道具有标识符,能够被其他进程找到,因此可以用于同一主机上的任意进程间通信。

管道分类——1.匿名管道

使用管道实现传输:
a进程想要进行数据传输,他先在内核空间创建了一个管道,管道向a返回文件描述符,A进程的子进程b创建,复制了a进程(父进程)的文件描述符(管道操作句柄),两个进程同时访问一块内核空间,完成数据传输(如下图)
在这里插入图片描述

  1. 匿名管道就像是家族财产,只有同一个家族的人才有操作句柄能操作,子进程复制父进程,会复制到同一个管道的操作句柄因此能够访问同一个管道
  2. 操作句柄:文件描述符通过文件描述符这个下标,就能找到管道的描述信息,进而找到管道进行操作
  3. 发送数据就是向管道写入数据,接收数据就是从管道读取数据

管道的本质是内核中的一块缓冲区,但是linux下一切皆文件,因此把管道也当做文件来处理注意:有些文章上说管道是-种特殊的文件(不是传统意义上的磁盘文件), 本质是内存

由下图我们可以观察,只要是同一个家族的进程,都会复制相同的操作句柄,才会进行通信,所以创建管道一定要在创建子进程之前
在这里插入图片描述
注意:
打开一个文件才会有句柄,创建了管道才会有句柄,但是,一个程序运行起来之后,默认就会打开三个文件:标准输入,标准输出,标准错误

#include <unistd.h>
功能:创建一无名管道
原型
int pipe(int fd[2]);
参数
fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
返回值:成功返回0,失败返回错误代码

在这里插入图片描述

匿名管道举例

实例代码(一):

在这里插入图片描述
运行结果:
在这里插入图片描述
实例代码(二):
在这里插入图片描述

如果管道中没有数据,read会阻塞,一直等到数据写入才会返回。
如果管道中数据满了,write会阻塞,直到有数据取出才会继续写入
管道的所有读端被关闭,则继续向管道写入数据会导致进程崩溃退出 ,其本质就是读端关闭之后,再往进去写就没有意义了,所以进程就被系统给干掉了
管道的所有写端被关闭,则read从管道读取完所有数据后,将不再阻塞,而是返回0

管道如果所有能够写入数据的描述符被关闭了,意味着管道中已经不可能有数据再进来了,因此也没有必要继续等待了,当read从管道中读取数据的时候,返回了 0 意味着这个管道已经不可能读到数据了,没必要再继续读了,因此可以通过red的返回值来决定什么时候停止从管道读取数据

管道的特点

只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创
建,然后该进程调用fork,此后父、子进程之间就可应用该管道。
管道提供流式服务 一般而言,进程退出,管道释放,所以管道的生命周期随进程
一般而言,内核会对管道操作进行同步与互斥 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道

在这里插入图片描述
举例:
ps -ef | grep pipel
|管道符: 连接两个命令,将前边命令的输出结果,交给后边命令进行处理。

思考:这个命令底层是怎么实现的?

其实执行一个指令,就是创建了一个子进程,程序替换运行了一个指令对应的程序,因此ps -ef | grep pipe1就是创建了两个进程运行了两个命令程序。因此现在要做的就是将ps进程的结果,交给grep进程ps -ef的结果:打印输出(将进程信息,写入到标准输出文件)grep pipe1的结果:捕捉标准输入的数据,进行过滤输出

实现:
1.父进程创建管道
2.创建子进程1,将子进程1的标准输出重定向到管道的写入端,程序替换为ps程序 这时候ps进程向标准输出写入数据,其实就是向管道写入数据
3.创建子进程2,将子进程2的标准输入重定向到管道的读取端,程序替换为grep程序 这时候grep程序从标准输入读取数据,其实就是从管道读取数据

实现代码:

在这里插入图片描述

管道分类——2.命名管道

本质:内核中的一块缓冲区,但是有自己的的名字,能够被其他进程找到,因此可以用于同一主机上任意进程的通信,所以命名管道的原理就是,一个进程创建了一个命名管道的名字,多个进程通过相同的管道名字,打开同一个管道,访问同一块内存缓冲区。

命名管道的名字:是一个可见的文件系统的管道文件
注意:命名管道文件虽然是一个文件,但是其实上是一个名字,能够让多个进程打开同一个命名管道文件,进而获取到同一个管道缓冲区的描述信息或者说操作句柄,进而访问同一块缓冲区进行通信,实质上还是内核内的缓冲区完成的,而不是文件。
在这里插入图片描述
管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。命名管道是一种特殊类型的文件

注意:一个管道的创建并不涉及缓冲区的创建因为如果管道创建了没有使用的话,缓冲区会一直存在,这样不划算,故只有在使用的时候才会涉及缓冲区创建。

创建一个命名管道

命名管道可以从命令行上创建,命令行方法是使用下面这个命令:

$ mkfifo filename

命名管道也可以从程序里创建,相关函数有:

int mkfifo(const char *filename,mode_t mode);//名称   操作权限
//成功返回0 失败返回 -1

创建命名管道:

int main(int argc, char *argv[])
{
mkfifo("p2", 0644);
return 0;
}

举例

1.写端举例:
在这里插入图片描述
解释:不使用O_CREAT,因为如果管道文件不存在,这里也是创建了一个普通的文件,EEXIST是用来判断本来存在吗,存在返回真,不存在返回假,注意这里的fflush,刷新缓冲区写入文件

2.读端举例

在这里插入图片描述
注意:若使用只写的方式写入的时候,会阻塞,直到管道被任意一个程序读;若使用只读的方式读取的时候,会阻塞,直到管道被任意一个程序写入。

命名管道的打开规则

如果当前打开操作是为读而打开FIFO时
 O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO
 O_NONBLOCK enable:立刻返回成功
如果当前打开操作是为写而打开FIFO时
 O_NONBLOCKdisable:阻塞直到有相应进程为读而打开该FIFO
 O_NONBLOCK enable:立刻返回失败,错误码为ENXIO

匿名管道与命名管道的区别

1.匿名管道由pipe函数创建并打开。
2.命名管道由mkfifo函数创建,打开用open
3.FIFO(命名管道)与pipe(匿名管道)之间唯一的别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义。

注意:管道自带同步与互斥
互斥:通过同一时间的唯一访问, 来保证访问的安全性
 管道的读写操作在不超过PIPE_ BUF-4096字节大小时,保证原子性。——原子性:不可分割特性;原子操作: 一个操作不会被打断
同步:通过对资源的访问进行一-些条件限制, 让进程对资源的访问更加合理
 管道中没有数据,则read会阻塞;管道中数据满了 ,则write会阻塞

具体使用举例:

例子1-用命名管道实现文件拷贝

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
int main(int argc, char* argv[])
{
	mkfifo("tp", 0644);
	int infd;
	infd = open("abc", O_RDONLY);
	if (infd == -1) ERR_EXIT("open");
	int outfd;
	outfd = open("tp", O_WRONLY);
	if (outfd == -1) ERR_EXIT("open");
	char buf[1024];
	int n;
	while ((n = read(infd, buf, 1024)) > 0)
	{
		write(outfd, buf, n);
	}
	close(infd);
	close(outfd);
	return 0;
}

读取管道,写入目标文件:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
int main(int argc, char* argv[])
{
	int outfd;
	outfd = open("abc.bak", O_WRONLY | O_CREAT | O_TRUNC, 0644);
	if (outfd == -1) ERR_EXIT("open");
	int infd;
	infd = open("tp", O_RDONLY);
	if (outfd == -1)
		ERR_EXIT("open");
	char buf[1024];
	int n;
	while ((n = read(infd, buf, 1024)) > 0)
	{
		write(outfd, buf, n);
	}
	close(infd);
	close(outfd);
	unlink("tp");
	return 0;
}

例子2-用命名管道实现server&client通信

# cat Makefile
.PHONY:all
all:clientPipe serverPipe
clientPipe:clientPipe.c
gcc -o $@ $^
serverPipe:serverPipe.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -f clientPipe serverPipe
int main()

serverPipe.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#define ERR_EXIT(m) \
do{\
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
int main()
{
	umask(0);
	if (mkfifo("mypipe", 0644) < 0) {
		ERR_EXIT("mkfifo");
	}
	int rfd = open("mypipe", O_RDONLY);
	if (rfd < 0) {
		ERR_EXIT("open");
	}
	char buf[1024];
	while (1) {
		buf[0] = 0;
		printf("Please wait...\n");
		ssize_t s = read(rfd, buf, sizeof(buf) - 1);
		if (s > 0) {
			buf[s - 1] = 0;
			printf("client say# %s\n", buf);
		}
		else if (s == 0) {
			printf("client quit, exit now!\n");
			exit(EXIT_SUCCESS);
		}
		else {
			ERR_EXIT("read");
		}
	}
	close(rfd);
	return 0;
}

clientPipe.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define ERR_EXIT(m) \
do{\
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
int main()
{
	int wfd = open("mypipe", O_WRONLY);
	if (wfd < 0) {
		ERR_EXIT("open");
	}
	char buf[1024];
	while (1) {
		buf[0] = 0;
		printf("Please Enter# ");
		fflush(stdout);
		ssize_t s = read(0, buf, sizeof(buf) - 1);
		if (s > 0) {
			buf[s] = 0;
			write(wfd, buf, strlen(buf));
		}
		else if (s <= 0) {
			ERR_EXIT("read");
		}
	}
	close(wfd);
	return 0;
}

结果:
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/193887.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

POI介绍简介

2.1 POI介绍 Apache POI是用Java编写的免费开源的跨平台的Java API&#xff0c;Apache POI提供API给Java程序对Microsoft Office格式档案读和写的功能&#xff0c;其中使用最多的就是使用POI操作Excel文件。 jxl&#xff1a;专门操作Excel maven坐标&#xff1a; <depend…

Linux中安装MySQL及常见问题汇总

一、安装前工作 1、卸载之前的数据库 在安装前需要确定现在这个系统有没有 mysql&#xff0c;如果有那么必须卸载 &#xff08;在 centos7 自带的是 mariaDb 数据库&#xff0c;所以第一步是卸载数据库&#xff09;。 #查看mariadb数据库&#xff1a; rpm -qa | grep maria…

moment.js根据时间戳计算与当前时间相差多少天

Moment旨在在浏览器和Node.js中工作。 所有代码都应该在这两种环境中都有效&#xff0c;并且所有单元测试都在这两种环境中运行。 目前&#xff0c;以下浏览器用于ci系统&#xff1a;Windows XP上的Chrome&#xff0c;Windows 7上的IE 8,9和10&#xff0c;Windows 10上的IE 1…

小车程序、安装vs2019和必要的相关软件

环境 sqlserver2019 vs2019企业版本 安装vs2019步骤 小车程序 C# .net vs2019 sqlserver2019 小车程序地址 小车运行的几种轨迹 一&#xff0c;自动运行到指定节点 找到manual按钮&#xff0c;找到目的节点&#xff0c;search move。 二&#xff0…

[数学] 三次样条

三次样条 已知有一组点x0,x1,x2,⋯,xnx_0, x_1, x_2, \cdots, x_nx0​,x1​,x2​,⋯,xn​, 其中, xt<xt1x_t<x_{t1}xt​<xt1​, y(xt)yty(x_t)y_ty(xt​)yt​, 及该点处的切线y′(xt)yt′y(x_t)y_ty′(xt​)yt′​ 每两个相邻的点之间可以作一个三次曲线 在所有相邻…

let/const相关内容(二)

let/const作用域提升 1&#xff09;根据前面所学的内容知道&#xff0c;var定义的变量是可以作用域提升的。 console.log(foo); // undefined var foo "foo"虽然在第一行中foo还没有被定义&#xff0c;但是在执行代码前&#xff0c;会预编译&#xff0c;先定义f…

ModStartBlog v6.6.0 多语言增强,缓存后台优化

ModStart 是一个基于 Laravel 模块化极速开发框架。模块市场拥有丰富的功能应用&#xff0c;支持后台一键快速安装&#xff0c;让开发者能快的实现业务功能开发。 系统完全开源&#xff0c;基于 Apache 2.0 开源协议。 功能特性 丰富的模块市场&#xff0c;后台一键快速安装会…

【完美解决】Github action报错remote: Write access to repository not granted.

报错及效果图报错代码效果图解决方案必要步骤可能有效的步骤报错及效果图 本解决方案是笔者通过Github action运行项目时报错的解决方案&#xff0c;如果是本地运行报此错&#xff0c;未必有效果。 报错代码 remote: Write access to repository not granted. fatal: unable t…

密评FAQ:如何确定网络和通信安全层面的测评对象?

信息系统一般通过网络技术来实现与外界的互联互通&#xff0c;GB/T 39786-2021《信息安全技术信息系统密码应用基本要求》规定了信息系统在网络和通信安全层面的密码应用技术要求&#xff0c;这些要求涉及到通信的主体&#xff08;通信双方&#xff09;、信息系统与网络边界外建…

(1)深入理解Java虚拟机-内存模型

深入理解Java虚拟机 Java虚拟机运行时数据区 程序计数器 ​ 程序计数器&#xff08;Program Counter Register&#xff09;是一块较小的内存空间&#xff0c;它可以看作是当前线程所执行的 字节码的行号指示器。在Java虚拟机的概念模型里 [1] &#xff0c;字节码解释器工作时…

大学开学必备清单、大学生必备的五件电子产品

转眼间就到了新一年的春季开学&#xff0c;在校生进入了新的一个年级学习。电子产品早就成为每个人的必备&#xff0c;尤其是大学生在校时期&#xff0c;更是上网课、日常查询资料的必备&#xff0c;当然还有一些社交、娱乐的因素也都是通过各式各样的电子产品来满足和实现。接…

android12 rockchip预置APK流程

方法一&#xff1a; 根据RK文档&#xff0c; 预制APK很简单, 首先source 环境之后执行命令&#xff1a;get _build_var TARGET_DEVICE_DIR 查看目标文件夹&#xff0c; 例如: device/rockchip/rk3568s/ 这个目录有三个文件夹&#xff1a; preinstall 不可卸载 preinstall_del_f…

基于text2vec进行文本向量化、聚类

基于text2vec进行文本向量化、聚类基于text2vec进行文本向量化、聚类介绍安装安装text2vec库安装transformers库模型下载文本向量化使用text2vec使用transformers文本聚类训练流程&#xff1a;训练代码推理流程推理代码基于text2vec进行文本向量化、聚类 介绍 文本向量表征工…

21_ncwireshark

nc&wireshark 一、nc介绍 网上百度就有一堆介绍,平常主要用于监听和连接 二、nc判断端口是否开放 实验环境: win10虚拟机和kali虚拟机 win10虚拟机ip: 192.168.11.142 kali虚拟机ip: 192.168.11.131 此时win10虚拟机,开放了80端口,21端口,3306端口 在kali虚拟机使用…

【书】只会功能测试的我,核心竞争力在哪里?

在现实工作中&#xff0c;测试的工作在很多人眼里就是“点点点”&#xff0c;特别是在推进开发自测或者向上级回报的时候&#xff0c;测试的工作显得那么平白无奇。 不仅是在公司内部&#xff0c;在进行面试的时候也会被问到&#xff0c;你觉得你的优势在哪里&#xff1f; 以上…

BlockingQueue(阻塞队列)详解

一. 前言 在新增的Concurrent包中&#xff0c;BlockingQueue很好的解决了多线程中&#xff0c;如何高效安全“传输”数据的问题。通过这些高效并且线程安全的队列类&#xff0c;为我们快速搭建高质量的多线程程序带来极大的便利。本文详细介绍了BlockingQueue家庭中的所有成员&…

上海亚商投顾:A股三大指数震荡涨跌各异 大消费全天活跃

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。市场情绪沪指今日窄幅震荡&#xff0c;创业板指小幅冲高后回落&#xff0c;科创50指数盘中涨近1.5%&#xff0c;随后涨幅明显…

gdb与gdbserver的使用

GDB调试示例以调试可执行程序gdbDebug为例&#xff0c;gdbDebug.cpp内容如下&#xff1a;使用gdb 启动gdbDebug程序左侧为gdb调试&#xff0c;右侧为gdbDebug.cpp内容GDB与GDBServer调试示例以调试可执行程序gdbDebug为例&#xff0c;gdbDebug.cpp内容如下&#xff1a;使用gdbs…

StarRocks荣获2022年度最具潜力数据库奖

近日&#xff0c;墨天轮颁布了《2022年度数据库获奖名单》&#xff0c;通过墨天轮排行榜排名及年度得分、生态建设、市场活动、市场份额、专利数等38个综合指标进行遴选&#xff0c;评选出2022年的数据库重要奖项&#xff0c;期望能够通过多维度评选&#xff0c;呈现出数据库产…

客户在国内,挑选海外服务器供应商有什么技巧?

​  一直以来&#xff0c;基于互联网管理的严格要求&#xff0c;在使用中国大陆服务器放置网站时&#xff0c;是需要备案手续的&#xff0c;这个手续时长快则7天&#xff0c;慢则也有接近1个月的情况&#xff0c;复杂耗时&#xff0c;当然&#xff0c;这也是对建站成本的增加…