【Linux】进程间通信---匿名管道、命名管道(超详解)

目录

匿名管道

管道的创建:

创建子进程:

关闭不需要的fd:

发送消息:

管道的5种特征:

管道的4种情况:

命名管道

创建命名管道:

删除命名管道:

手写命名管道:

完整代码:


我们先来回答下面的几个问题再来正式的进入管道的学习;

 1、进程为什么要通信?

进程是需要某种协同的,所有如何协同的前提条件是通信-->数据是有类别的-->通知就绪的、单纯的传递数据的、控制相关信息的...

2、进程如何通信?

a、进程间通信,成本可能会比较高

b、进程间通信前提:先让不同进程看到同一份(操作系统)资源(“一份内存”)

3、进程通信的常用方式

1、system V

2、Posix

我们重点讨论system V方式:有三种

  1. 消息队列
  2. 内存共享(重点讨论)
  3. 信号量

如何直接复原内核代码直接通信呢?

管道:

        1、命名管道

        2、匿名管道

匿名管道

#include <unistd.h>

int pipe(int pipefd[2]);

pipefd[2]:文件描述符数组,pipefd[0]:readpipefd[1]:write;

返回值:管道创建成功返回0,创建失败返回错误代码

巧记方法:

        0--->嘴巴--->r

        1--->钢笔--->w

匿名管道之所以叫匿名管道,是因为它不需要文件名和文件路径;

一个进程打开一个文件时,会以读方式打开和写方式两种方式分别打开;也就是会形成两个file文件;但是第二次打开同一个文件的时候,文件的inode,操作方法集合,缓冲区不会再加载一次了;会指向第一次打开文件时候加载的地址;

为什么父子进程会指向同一个显示器终端打印文件?

子进程会指向父进程的文件描述符表,进而会指向同一个文件;

进程默认会打开三个标准输出:0、1、2,怎么做到的呢?

所有的进程都是bash的子进程,bash打开了,所有的子进程也就默认打开了;

close();为什么子进程主动close(0/1/2);不影响父进程继续使用显示器文件呢?

在file中有一个引用计数ref_count,子进程关闭时,ref_count--;只有ref_count为0时,才会释放文件资源;(注意:这里的引用计数和硬链接里的引用计数不同,但是原理是类似的)

为什么父进程读写后在fork?(看图中的1,2)

本质是为例让父子进程看到同一份资源;

管道的创建:

#include<iostream>
#include<unistd.h>
#include<cerrno>
#include<cstring>
using namespace std;int main()
{//1、创建管道int pipfd[2];int n =pipe(pipfd);//输出型参数,rfd,wrdif(n!=0){cerr<<"errno:"<<errno<<":"<<"errstring:"<<strerror(errno)<<endl;}//管道创建成功cout<<"pipfd[0]:"<<pipfd[0]<<" pipfd[1]"<<pipfd[1]<<endl;return 0;
}

运行结果:

通过观察运行结果,我们可以证明文件被打开了两次

创建子进程:

 pid_t id=fork();

关闭不需要的fd:

如果是父进程读取,子进程写入的话;父进程就要close(1);子进程close(0);

如果是父进程写入,子进程读取的话;父进程就要close(0);子进程close(1);

最后要记得添加一个waitpid,使整个代码完整;

发送消息:

怎么发送呢?

管道也是文件,所以发送信息可以直接用系统的read/write

void childwrite(int wfd)
{string message="child process";//发送给父进程的信息while(true){write(wfd,message.c_str(),message.size());//写入管道时,没有写入\0,没有必要写入;sleep(1);}
}void   father_read(int rfd)
{char inbuffer[size];while(true){ssize_t n=read(rfd,inbuffer,sizeof(inbuffer)-1);if(n>0){inbuffer[n]=0;cout<<"father get message:"<<inbuffer<<endl;}}}

运行结果:

父进程确实接收到了子进程发送的 信息,因此通信完成;

管道的5种特征:

  1. 匿名管道:只用来直接进行具有血缘关系的进程之间,进程通信,常用父子进程之间通信
  2. 管道内部,自带进程之间的同步机制--------->多执行流文件的时候,具有明显的顺序性!
  3. 管道文件的生命周期是随进程的
  4. 管道文件在通信的时候,是面向字节流的  ----->w次数和r次数是不匹配的
  5. 管道的通信模式是一种特殊的半双工模式

管道的4种情况:

  1. 如果管道内部是空的&&write fd 没有关闭,读取条件不具备,读进程会被阻塞 --->wait --->读取条件具备 --->写入数据
  2. 管道被写满&&read fd 不读且没有关闭,管道被写满,写进程会被阻塞 --->写条件不具备-->写条件具备 ----->读取数据
  3. 管道一直在读 && 写段关闭wfd,读端read返回值会读到0,表示读到了文件结尾
  4. rid直接关闭,写端wfd一直进行写入?-->写端进程会被操作系统直接使用13信号关掉,相当于进程出现了异常

命名管道

对于命名管道的原理可以看下面的图,图中很详细的表明了命名管道的内核结构;

创建命名管道:

mkfifo 管道名

我们可以通过向管道中写入一下内容,并查看是否可以读取,来检查管道是否创建成功;

注意:我们查看管道文件的大小是会发现管道文件依旧是0

删除命名管道:

unlink 管道名

手写命名管道:

用的是mkfifo系统调用;

第一个参数是路径,第二个参数是权限;(可以回忆一下umask

运行一下来验证管道是否创建成功:

(2)管道创建成功后,我们就要打开这个管道文件;

(3)打开文件后,我们就要开始写操作和读操作;

这里我们的server进程读操作,client进程写操作;

运行一下,来检验:

注意一下:

这里我们的读操作不能像下面一下来写,不然会报段错误:

报错的原因是:sizeof(out);

sizeof(out)其实是指针本身的大小,不是字符串数据的大小;

完整代码:

这只是.hpp文件的代码;

#pragma once#include <iostream>
#include <string>
#include<cstdio>
#include<cerrno>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>using namespace std;const string comm_path = "./fifo";
#define gCreater 1
#define gUser 2
#define Read O_RDONLY
#define Write O_WRONLY
#define FD -1
#define SIZE 4069
class namepipe
{
private:bool openpipe(int flag){_fd = open(_path.c_str(), flag);if (_fd < 0){return false;}return true;}public:namepipe(const string &path, int who) : _path(path), _id(who),_fd(FD){if (_id == gCreater){int res = mkfifo(path.c_str(), 0666);cout << "namepipe create sucess" << endl;}}~namepipe(){if (_id == gCreater){int res = unlink(_path.c_str());if (res == 0){cout << "namepipe remove sucess" << endl;}if(_fd!=FD){close(_fd);}}}bool open_readpipe(){return openpipe(Read);}bool open_writepipe(){return openpipe(Write);}int readpipe(string * out){char buff[SIZE];int n=read(_fd,buff,sizeof(buff));if(n>0){buff[n]=0;*out=buff;}return n;}int writepipe(const string & in){write(_fd,in.c_str(),sizeof(in));}
private:const string _path;int _id;int _fd;
};

客户端代码比较简单,这里我就直接放图片了:

server.cpp:

client.cpp:

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

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

相关文章

多线程(七):单例模式指令重排序

目录 1. 单例模式 1.1 饿汉模式 1.2 懒汉模式 2. 懒汉模式下的问题 2.1 线程安全问题 2.2 如何解决 --- 加锁 2.3 加锁引入的新问题 --- 性能问题 2.4 指令重排序问题 2.4.1 指令重排序 2.4.2 指令重排序引发的问题 1. 单例模式 单例模式, 是设计模式中最典型的一种模…

Vision China 2024 | 移远通信以一体化的AI训练及部署能力,引领3C电子制造智能升级

10月14日&#xff0c;由机器视觉产业联盟(CMVU)主办的中国机器视觉展(Vision China)在深圳国际会展中心盛大开幕。作为全球领先的物联网整体解决方案供应商&#xff0c;移远通信应邀参加展会首日举办的“智造引领数质并进”3C电子制造自动化与数字化论坛。 论坛上&#xff0c;移…

PostgreSQL学习笔记:PostgreSQL vs MySQL

PostgreSQL 和 MySQL 都是广泛使用的关系型数据库管理系统&#xff0c;它们有以下一些对比&#xff1a; 一、功能特性 1. 数据类型支持 PostgreSQL&#xff1a;支持丰富的数据类型&#xff0c;包括数组、JSON、JSONB、范围类型、几何类型等。对于复杂数据结构的存储和处理非…

rancher安装并快速部署k8s 管理集群工具

主机准备 准备4台主机 3台用于k8s集群 &#xff0c;1台用于rancher 每台服务器新增配置文件 vi etc/sysctl.confnet.ipv4.ip_forward 1 刷新生效 sysctl –p 安装docker 安装的时候可以去github上检索rancher看看最新版本适配那个版本的docker&#xff0c;这里安装23.0.1…

酸碱PH值与浓度关系

1. 硫酸百分比浓度是指溶液中硫酸的质量占溶液总质量的百分比。‌ 例如&#xff0c;如果100克溶液中含有98克的硫酸&#xff0c;那么硫酸的百分比浓度为98% 2. 1mol/L硫酸对应百分比浓度多少&#xff1f;答&#xff1a;硫酸的质量分数98&#xff0c;1mol/L硫酸98g/L9.8%的硫酸…

RNN,LSTM,GRU的区别和联系? RNN的梯度消失问题?如何解决?

RNN&#xff0c;LSTM&#xff0c;GRU的区别和联系? RNN&#xff08;Recurrent Neural Network&#xff09;、LSTM&#xff08;Long Short-Term Memory&#xff09;和GRU&#xff08;Gated Recurrent Unit&#xff09;都是用于处理序列数据的神经网络模型&#xff0c;它们之间…

动态规划:17.简单多状态 dp 问题_买卖股票的最佳时机III_C++

题目链接&#xff1a; 一、题目解析 题目&#xff1a;123. 买卖股票的最佳时机 III - 力扣&#xff08;LeetCode&#xff09; 解析&#xff1a; 拿示例1举例&#xff1a; 我们可以如图所示买入卖出股票&#xff0c;以求得最大利润&#xff0c;并且交易次数不超过2次 拿示…

二百六十九、Kettle——ClickHouse清洗ODS层原始数据增量导入到DWD层表中

一、目的 清洗ClickHouse的ODS层原始数据&#xff0c;增量导入到DWD层表中 二、实施步骤 2.1 newtime select( select create_time from hurys_jw.dwd_statistics order by create_time desc limit 1) as create_time 2.2 替换NULL值 2.3 clickhouse输入 2.4 字段选择 2.5 …

Git的原理和使用(三)

1. 分支管理 1.1 合并模式 1.1.1 fast forward模式 git log --graph --abbrev-commit 1.1.2 no-ff模式 合并出现问题后需要进行手动修改&#xff1a; 如下图所示&#xff1a; 1.1.3 不使用no-ff模式 git merge --no-ff -m "merge dev2" dev2 1.2 分⽀策略 在实际开…

多IP访问多网段实验

文章目录 多IP访问多网段实验 多IP访问多网段实验 在当前主机配置多个IP地址&#xff0c;实现多IP访问多网段&#xff0c;记录所有命令及含义 1&#xff0c;环境搭建&#xff1a; [rootlocalhost ~]# mount /dev/sr1 /mnt # 设置ISO虚拟镜像文件文件挂载点&#xff0c;将…

数据分析和可视化python库orange简单使用方法

Orange 是一个基于 Python 的数据挖掘和机器学习库&#xff0c;它提供了一系列可视化工具和算法&#xff0c;用于数据分析、机器学习和数据可视化等任务。 一、主要特点 可视化界面&#xff1a;Orange 提供了直观的可视化界面&#xff0c;使得用户可以通过拖放操作构建数据分…

【python爬虫实战】爬取全年天气数据并做数据可视化分析!附源码

由于篇幅限制&#xff0c;无法展示完整代码&#xff0c;需要的朋友可在下方获取&#xff01;100%免费。 一、主题式网络爬虫设计方案 1. 主题式网络爬虫名称&#xff1a;天气预报爬取数据与可视化数据 2. 主题式网络爬虫爬取的内容与数据特征分析&#xff1a; - 爬取内容&am…

算法(四)前缀和

前缀和也是一个重要的算法&#xff0c;一般用来快速求静态数组的某一连续区间内所有数的和&#xff0c;效率很高&#xff0c;但不支持修改操作。分为一维前缀和、二维前缀和。 重要的前言&#xff01; 不要死记模板&#xff0c;具体题目可能是前缀和、前缀乘积、后缀和、后缀乘…

已解决:ModuleNotFoundError: No module named ‘pip‘

[已解决] ModuleNotFoundError: No module named ‘pip‘ 文章目录 写在前面问题描述报错原因分析 解决思路解决办法1. 手动安装或升级 pip2. 使用 get-pip.py 脚本3. 检查环境变量配置4. 重新安装 Python 并确保添加到 PATH5. 在虚拟环境中安装 pip6. 使用 conda 安装 pip&…

无人机电机故障率骤降:创新设计与六西格玛方法论双赢

项目背景 TBR-100是消费级无人机头部企业推出的主打消费级无人机&#xff0c;凭借其出色的续航能力和卓越的操控性&#xff0c;在市场上获得了广泛认可。在产品运行过程&#xff0c;用户反馈电机故障率偏高&#xff0c;尤其是在飞行一段时间后出现电机过热、损坏以及运行不稳定…

《深度学习》dlib 人脸应用实例 仿射变换 换脸术

目录 一、仿射变换 1、什么是仿射变换 2、原理 3、图像的仿射变换 1&#xff09;图像的几何变换主要包括 2&#xff09;图像的几何变换主要分为 1、刚性变换&#xff1a; 2、仿射变换 3、透视变换 3&#xff09;常见仿射变换 二、案例实现 1、定义关键点索引 2、定…

OpenHarmony 入门——ArkUI 自定义组件内同步的装饰器@State小结(二)

文章大纲 引言一、组件内状态装饰器State1、初始化2、使用规则3、变量的传递/访问规则说明4、支持的观察变化的场景5、State 变量的值初始化和更新机制6、State支持联合类型实例 引言 前一篇文章OpenHarmony 入门——ArkUI 自定义组件之间的状态装饰器小结&#xff08;一&…

100多种【基于YOLOv8/v10/v11的目标检测系统】目录(python+pyside6界面+系统源码+可训练的数据集+也完成的训练模型)

待更新(持续更新&#xff09;&#xff0c;早关注&#xff0c;不迷路............................................................................... 基于YOLOv8的车辆行人实时检测系统基于YOLOv10的车辆行人实时检测系统基于YOLOv11的车辆行人实时检测系统基于YOLOv8的农…

如何在UE5中创建加载屏幕(开场动画)?

第一步&#xff1a; 首先在虚幻商城安装好Async Loading Screen&#xff0c;并且在项目的插件中勾选好。 第二步&#xff1a; 确保准备好所需要的素材&#xff1a; 1&#xff09;开头的动画视频 2&#xff09;关卡加载图片 3&#xff09;准备至少两个关卡 第三步&#xff1a…

PythonExcel批量pingIP地址

问题&#xff1a; 作为一个电气工程师&#xff08;PLC&#xff09;&#xff0c;当设备掉线的时候&#xff0c;需要用ping工具来检查网线物理层是否可靠连接&#xff0c;当项目体量过大时&#xff0c;就不能一个手动输入命令了。 解决方案一&#xff1a; 使用CMD命令 for /L %…