【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,一经查实,立即删除!

相关文章

C语言:函数指针与指针函数的区别*

文章目录 一、函数指针定义语法 二、指针函数定义语法用途 三、函数指针与指针函数的区别本质不同&#xff1a;声明方式&#xff1a; 四、结论 C语言&#xff1a;函数指针与指针函数的区别 在C语言这个充满灵活性和强大表达力的编程世界中&#xff0c;函数指针和指针函数是两个…

小班幼儿攻击性行为的现状研究-以德格县某幼儿园为例(开题报告)

毕业论文(设计)开题报告 题目 题目类别 毕业设计 姓名 专业 班级 学号 一、选题背景及依据(简述国内外研究状况和相关领域中已有的研究成果(文献综述),选题目的、意义,列出主要参考文献) (一)选题背景与依据 1、选题背景 幼儿教育作为个体一生教育的起点,对于儿童…

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

目录 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、范围类型、几何类型等。对于复杂数据结构的存储和处理非…

go基础(一)

包声明引入包函数变量语句&表达式注释 package main//包声明import "fmt"//引入包 //函数 func main() {/* 这是我的第一个简单的程序 */fmt.Println("Hello, World!") }基础语法 标记 go程序可以由多个标记组成&#xff0c;可以是关键字&#xff0…

【K8s】专题十四(2):Kubernetes 安全机制之 Security Context

本文内容均来自个人笔记并重新梳理&#xff0c;如有错误欢迎指正&#xff01; 如果对您有帮助&#xff0c;烦请点赞、关注、转发、订阅专栏&#xff01; 专栏订阅入口 | 精选文章 | Kubernetes | Docker | Linux | 羊毛资源 | 工具推荐 | 往期精彩文章 【Docker】&#xff08;全…

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…

centos升级g++使其支持c++17

centos升级g使其支持c17 升级g的原因现象原因 升级g方法更新镜像源yum升级g版本 总结 升级g的原因 现象 编译最新版本的jsoncpp报一下错误 jsontest.h:87:37: error: ‘hexfloat’ is not a member of ‘std’oss << std::setprecision(16) << std::hexfloat &l…

SQL注入笔记

SQL注入&#xff1a;一种常见的Web安全漏洞&#xff0c;形成的主要原因是web应用程序在接收相关数据参数时未做好过滤&#xff0c;将其直接带入到数据库中查询&#xff0c;导致攻击者可以拼接执行构造的SQL语句。 SQL注入的几个步骤&#xff1a; 1.寻找可能的注入点&#xff…

酸碱PH值与浓度关系

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

Vue2 和 Vue3 的区别

文章目录 Vue2 和 Vue3 的区别核心架构的变化核心变化&#xff1a; 组合式 API&#xff08;Composition API&#xff09;对比&#xff1a;示例&#xff1a; 性能提升响应式系统改进TypeScript 支持TypeScript 的对比&#xff1a; Fragment 支持编译优化Tree-shaking 与更轻的运…

Android activity 启动流程

Android activity 启动流程 本文主要记录下acitivty的启动流程. 1: Activity 我们都知道启动activity调用方法: startActivity(Intent intent)startActivity(Intent intent, Nullable Bundle options)startActivityForResult(RequiresPermission Intent intent, int reques…

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次 拿示…

【mysql】ISNULL、NVL、IFNULL和COALESCE函数的使用方法

以下是 ISNULL、NVL、IFNULL 和 COALESCE 函数的详细使用方法&#xff1a; 1. ISNULL SQL Server 和 Sybase 使用 ISNULL 函数来处理空值。 语法&#xff1a; ISNULL(expression, replacement_value)参数&#xff1a; expression&#xff1a;要检查的表达式。replacement_…

二百六十九、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 分⽀策略 在实际开…

微服务发布

微服务架构下的灰度发布、蓝绿发布和滚动发布 灰度发布(又名金丝雀发布) 不停机旧版本&#xff0c;部署新版本&#xff0c;低比例流量(例如:5%)切换到新版本&#xff0c;高比例流量(例如:95%)仍走旧版本。通过监控观察确认无问题&#xff0c;逐步扩大范围&#xff0c;慢慢的把所…

多IP访问多网段实验

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