【linux】进程间通信——管道通信

news2025/1/18 16:47:29

进程间通信

  • 一、进程间通信
    • 1.1 通信的介绍
    • 1.2 通信的目的
    • 1.3 通信的分类
  • 二、管道
    • 2.1 匿名管道
      • 2.1.1 pipe
      • 2.2.2 读写特征
      • 2.2.3 命名管道

一、进程间通信

1.1 通信的介绍

通信就是一个进程把数据传递给另一个进程,但是每个进程都具有独立性。通信的本质:OS需要直接或者间接给通信双方的进程提供“内存空间”,并且要通信的进程,必须看到一份公共的资源

1.2 通信的目的

数据传输: 一个进程需要将它的数据发送给另一个进程
资源共享: 多个进程之间共享同样的资源
通知事件: 一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)
进程控制: 有些进程希望完全控制另一个进程的执行(如Debug进程)

为什么要进行通信?

因为我们有时需要多进程协同,例如管道。

1.3 通信的分类

1️⃣ 采用标准的做法:System V进程间通信(聚焦在本地通信,如共享内存)、POSIX进程间通信(让通信过程可以跨主机)。
2️⃣ 采用文件的做法:管道-基于文件系统(匿名管道、命名管道)

二、管道

我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”

我们知道要进行通信要指向同一块空间,所以我们可以让父进程打开一个文件,然后创建子进程,这样父子进程就会指向同一个文件,这样就可以在同一分文件中进行交流。
在这里插入图片描述

两个进程看到同一份资源,让一个进程写,另一个进程读,就可以完成进程间通信,这个文件成为管道文件

但是我们知道往文件里写就要与磁盘进行IO,效率大大降低。

任何一个文件包括两套资源:1.file的操作方法 2.有属于自己的内核缓冲区,父进程可以向对应的文件的文件缓冲区写入,子进程可以通过文件缓冲区读取,此时就完成了进程间通信,这种方式提供的文件称为管道文件。管道文件本质就是内存级文件,不需要IO。

这种管道叫做匿名管道。

2.1 匿名管道

我们知道我们如果以读的方式打开文件,那么子进程也会默认为读方式打开。
所以我们分别以读写方式打开同一个文件,子进程也会继承读写。接下来我们关闭一个进程的读端,再关闭另一个进程的写端(当然也可以不关,但为了防止其他进程使用,还是建议关闭),这样就让不同的进程看到同一份文件。
在这里插入图片描述
一般而言,管道只能用来进行单向数据通信。

那么怎么创建一个管道级文件呢?

2.1.1 pipe

在这里插入图片描述
它的参数是一个输出型参数,它可以帮我们分别以读和写的方式打开文件,然后把文件描述符填进数组返回

#include <iostream>
#include <unistd.h>
#include <cassert>

using namespace std;

int main()
{
    int fds[2];
    int n = pipe(fds);
    assert(n == 0);
    printf("fds[0] = %d\nfds[1] = %d\n", fds[0], fds[1]);
    return 0;
}

在这里插入图片描述
注意 0是读,1是写

至此我们成功创建了管道文件,打开了读写端。

#include <iostream>
#include <unistd.h>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <sys/wait.h>
#include <sys/stat.h>

using namespace std;

int main()
{
    // 创建管道文件
    int fds[2];
    int n = pipe(fds);
    assert(n == 0);
    // fork
    pid_t id = fork();
    if(id == 0)// 子
    {
        // 子进程通信
        close(fds[0]);// 关闭读
        int cnt = 0;
        while(1)
        {
            char buf[1024];
            snprintf(buf, sizeof(buf), "child->father: %s[%d]", "子进程发送", ++cnt);
            write(fds[1], buf, strlen(buf));
            sleep(1);
        }
        exit(0);
    }
    // 父进程通通信
    close(fds[1]);// 关闭写
    while(1)
    {
        char buf[1024];
        ssize_t s = read(fds[0], buf, sizeof(buf) - 1);
        if(s) buf[s] = '\0';// 补'\0'
        cout << "收到消息@ " << buf << endl;
    }
    waitpid(id, nullptr, 0);
    return 0;
}

在这里插入图片描述

2.2.2 读写特征

1️⃣ 读快写慢

子进程休眠,管道内没有数据,此时默认会直接阻塞当前正在读取的进程。

在这里插入图片描述
在这里插入图片描述
读完一次数据后,第二次就会卡在read处等待。

2️⃣ 读慢写快

写端一直在写,读端不读,而管道是有大小的,会被写满

在这里插入图片描述
在这里插入图片描述
当我们让父进程只等待两秒时:
在这里插入图片描述
他会按照指定的大小读取(sizeof(buf) - 1)。

3️⃣ 写关闭,读到0
在这里插入图片描述
4️⃣ 读取关闭,写入

如果是关闭读端,OS会终止写端,并会给写进程发送信号终止进程

在这里插入图片描述

管道特征:

1.管道的生命周期随进程,进程退出,管道释放
2.管道可以用来进行具有血缘关系的进程间通信(常用于父子通信)
3.管道是面向字节流的
4.半双工—单向通信(特殊)
5.互斥与同步机制——对共享资源进行保护的方案

2.2.3 命名管道

我们知道匿名管道只能在有血缘关系的进程间进行通信。
那么没有关系的进程之间就要用命名管道。
可以使用FIFO文件来做这项工作,它经常被称为命名管道,命名管道是一种特殊类型的文件

使用mkfifo命令创建命名管道

在这里插入图片描述
在这里插入图片描述
一个进程往管道文件中写入,另一个进程从管道中读取。就完成了进程间的通信。
在这里插入图片描述
在这里插入图片描述
这里要注意,往管道文件中写入和读取的时候大小一直为0

两个进程打开同一个文件:第二个文件不需要继续创建struct_file对象,直接指向第一个文件的struct_file。在内核中,此时就看到了同一份资源,有着操作方法和缓冲区,不需要把数据刷新到磁盘上去,不需要IO。所以无论是匿名还是命名,本质都是管道。

因为命名管道是通过让不同的进程打开指定名称的同一个文件(因为路径+文件名具有唯一性)。

创建自己的管道文件
我们先创建一个管道文件,首先要让两个进程看到同一份文件。comm.hpp
创建管道文件函数:
在这里插入图片描述
comm.hpp

#include <string>

#define NAME_PIPE "./mypipe"

using namespace std;

bool creatfifo(const string& path)
{
    int n = mkfifo(path.c_str(), 0666);
    if(!n) return true;
    else
    {
        cout << "errno mkfifo" << endl;
        return false;
    }
}

test1.cc

#include "comm.hpp"

using namespace std;

int main()
{
    bool flag = creatfifo(NAME_PIPE);
    assert(flag);
    return 0;
}

在这里插入图片描述
删除管道文件
删除管道文件函数:
在这里插入图片描述
comm.hpp

void Delete(const string& path)
{
    int n = unlink(path.c_str());
    assert(n == 0);
}

test1.cc

int main()
{
    bool flag = creatfifo(NAME_PIPE);
    assert(flag);
    Delete(NAME_PIPE);
    return 0;
}

创建和删除管道文件已经完成,我们就可以开始通信了。
test1.cc

#include "comm.hpp"

int main()
{
    bool flag = creatfifo(NAME_PIPE);
    assert(flag);

    int rfd = open(NAME_PIPE, O_RDONLY);// 只读
    if(rfd < 0) exit(1);
    // read
    char buf[1024];
    while(true)
    {
        ssize_t s = read(rfd, buf, sizeof(buf) - 1);
        if(s > 0)
        {
            cout << "test1->test2# " << buf << endl;
        }
        else if(s == 0)
        {
            cout << "test2 quit, me too!" << endl;
            break;
        }
        else
        {
            cout << "error" << endl;
            break;
        }  
    }
    close(rfd);
    Delete(NAME_PIPE);
    return 0;
}

test2.cc

#include "comm.hpp"

int main()
{
    int wfd = open(NAME_PIPE, O_WRONLY);// 只写方式打开同一份文件
    if(wfd < 0) exit(1);
    // write
    char buf[1024];
    while(true)
    {
        cout << "输入: ";
        fgets(buf, sizeof(buf), stdin);// 从键盘读取
        ssize_t n = write(wfd, buf, sizeof(buf));
        assert(n == strlen(buf));
    }
    
    close(wfd);
    return 0;
}

在这里插入图片描述

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

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

相关文章

STL——vector

一、标准库中的vector 1.vector文档介绍 &#xff08;1&#xff09;vector是表示可变大小数组的序列容器。 &#xff08;2&#xff09;像数组一样&#xff0c;vector也采用连续存储空间来存储元素&#xff0c;也就意味着可以采用下标对vector的元素进行访问&#xff0c;和数…

深度:用10000字总结了嵌入式C语言必学知识点

导读&#xff1a;怎么做好嵌入式&#xff1f;相信这个问题无论问谁你都会得到一句学好C语言&#xff01;今天推荐一篇大佬写的嵌入式C语言知识点总结&#xff0c;非常值得一读。 目录 1 关键字 2 数据类型 3 内存管理和存储架构 4 指针和数组 5 结构类型和对齐 6 预处理…

RDC 2022纪念版开发板-D1S在RT-Smart运行

开发环境 软件 ubuntu20.04VMware Workstation 硬件 RDC2022纪念版开发板全志D1s芯片 材料下载 首先打开虚拟机&#xff0c;创建一个目录存放本次测试的代码&#xff0c;然后克隆RT-Smart用户态代码。 git clone https://github.com/RT-Thread/userapps.git在userapps目…

SMB2协议特性之oplock与lease(下

前期回顾上篇文章我们介绍了oplock/lease的相关概念及其基本工作原理&#xff0c;由于间隔时间较长&#xff0c;忘记的读者可以先去回顾一下。本篇文章带大家了解一下&#xff0c;在实际场景中&#xff0c;oplock/lease是如何工作的。实际场景分析在一些警匪影视剧中&#xff0…

PCI驱动程序框架

PCI驱动程序框架 文章目录PCI驱动程序框架参考资料&#xff1a;一、 PCI驱动框架二、 RK3399驱动致谢参考资料&#xff1a; 《PCI Express Technology 3.0》&#xff0c;Mike Jackson, Ravi Budruk; MindShare, Inc.《PCIe扫盲系列博文》&#xff0c;作者Felix&#xff0c;这是…

【NS2】打印c++函数名字/bash将echo赋值给变量

需求&#xff1a;将tcl在c调用的路由算法名字&#xff08;函数名&#xff09;输出&#xff0c;并作为变量赋值给文件名字&#xff0c;但就怎么将函数名字打印出来就思考了很久&#xff0c;并尝试了其他网站“在shell脚本使用tcl变量、如何在bash脚本打印tcl变量、NS2&#xff0…

【实际开发12】- 经验 experience

目录 1. 经验 experience 1. 无多大价值 , 停留数据展示层面 2. 保证数据一致性问题 3. 新增时 , 可先关注核心基础数据 ( 复杂数据以修改形式完善 ) 4. 新增 / 修改 ( 幂等性处理 ) 5. 增 / 删 / 改 添加日志 , 查询无需日志 6. 需要对接多模块的通用字段设计 : String…

什么是CRM系统 企业如何选择合适的CRM系统

在如今市场竞争激烈情况下&#xff0c;企业更加注重客户的数据和管理&#xff0c;因此逐渐形成了“以客户为核心”的理念。而借助CRM系统管理客户数据已然成为一种趋势。 选择一款适合企业的CRM系统可以帮助企业实现更多的价值。但一些企业在初期根本不了解什么是CRM系统&…

Hadoop安装(一) --- JDK安装

目录 1.安装虚拟机 2.关防火墙 3.修改网络配置文件 4.重启网络服务 5.连接shell 6.安装vim工具 7.免密登陆 8. 开启远程免密登录配置 9.远程登录 10.同步时间 10.1.安装ntpdate 10.2.定时更新时间 10.3.启动定时任务 10.4.查看状态 11.修改计算机名 12.配置ho…

数据仓库的架构以及传统数据库与数据仓库的区别

一、数据仓库的分层架构 数据仓库的数据来源于不同的源数据&#xff0c;并提供多样的数据应用&#xff0c;数据自下而上流入数据仓库后向上层开放应用&#xff0c;而数据仓库只是中间集成化数据管理的一个平台。 1&#xff0c;源数据层&#xff08;ODS&#xff09; 操作性数…

袁树雄和杨语莲究竟什么关系 ,《早安隆回》走红后又是《汉川》

自从《早安隆回》火爆全网后&#xff0c;歌迷们就有一种担心&#xff0c;不知道这首好听的歌曲&#xff0c;究竟还能再够火爆多久。歌迷们的担心也不无道理&#xff0c;毕竟花无百日红&#xff0c;人无千般好&#xff0c;《早安隆回》就是再好听&#xff0c;也不可能红一辈子吧…

windows搭建go语言开发环境

1.下载Go语言开发包可以在Go语言官网 ( https://golang.google.cn/dl/ )下载Windows 系统下的Go语言开发包&#xff0c;如下图所示。这里我下载的是 64位的开发包&#xff0c;如果读者的电脑是 32 位系统的话&#xff0c;则需要下载 32 位的开发包&#xff0c;在上图所示页面中…

Fiddler手机抓包

手机抓包软件Fiddler 下载地址以及下载流程 Fiddler 下载地址&#xff1a;https://www.telerik.com/download/fiddler 下载后直接一键安装即可 重要的注意项卸载最前面 pc和手机需要在同一个局域网&#xff0c;也就是同一个wifi 配置 Fiddler界面的简单介绍 pc端Fildde…

Windows Server 2022 Install Veeam ONE 12

借助有关 Veeam Backup & Replication™ 和 Veeam Agents 及 VMware vSphere、Microsoft Hyper-V 和 Nutanix AHV 的洞察&#xff0c;Veeam ONE™ 可通过交互式工具和智能学习提供深度智能监控、报告和自动化功能&#xff0c;帮助客户发现问题并前瞻性地解决问题。 Veeam O…

CUDA编程之CUDA流

文章目录前言CUDA流在默认流中重叠主机与设备用非默认CUDA流重叠多个核函数的执行重叠多个核函数的例子用非默认CUDA流重叠核函数的执行与数据传递不可分页主机内存与异步的数据传输函数总结参考前言 CUDA程序的并行层次主要有两个&#xff0c;一个是核函数内部的并行&#xff…

C++面向对象——C++ 重载运算符和重载函数

C面向对象——C 重载运算符和重载函数C 重载运算符和重载函数C 中的函数重载C 中的运算符重载运算符重载实例C 一元运算符重载C 二元运算符重载C 关系运算符重载C 和 -- 运算符重载C 赋值运算符重载C 函数调用运算符 () 重载C 下标运算符 [] 重载C 类成员访问运算符 -> 重载…

三、进程通信

一、基础知识数据传输一个进程将他的数据发送给另一个进程资源共享多个进程间共享同样的资源通知时间一个进程向另一个进程发送消息&#xff0c;通知他们发生了某种事情通信方式&#xff1a;管道和有名管道信号signal消息队列共享内存信号量套接字二、管道&#xff1a;无名管道…

c++11 标准模板(STL)(std::multiset)(六)

定义于头文件 <set> template< class Key, class Compare std::less<Key>, class Allocator std::allocator<Key> > class multiset;(1)namespace pmr { template <class Key, class Compare std::less<Key>> usi…

基于python Django 餐馆点菜管理系统

问题描述&#xff1a; 随着网络的迅速发展&#xff0c;越来越多的人开始接受甚至时依赖了网络营业的这种交易形式&#xff0c;传统的点菜模式不仅浪费时间&#xff0c;效率低下&#xff0c;而且特别耗费成本与人力&#xff0c;因此不少商家开始使用网上点菜系统。网上点菜系统是…

皮尔森相关系数(Pearson correlation coefficient)

最近在看脑机接口的网络&#xff0c;看到有使用通道的皮尔森相关系数作为特征的方法&#xff0c;这里记录一下皮尔森相关系数的学习内容&#xff0c;方便以后查阅。 皮尔森相关系数(Pearson correlation coefficient&#xff09;相关系数简单相关系数复相关系数典型相关系数参考…