Linux进程间通信(基于管道通信)

news2024/12/26 10:38:00

目录

一、进程间通信

1.1 通信目的

1.2 通信发展

二、管道

2.1 管道的概念和分类

2.2 匿名管道

2.2.1 匿名管道(基于父子血缘关系)

2.2.2 匿名管道单向性

2.2.3 匿名管道是内存级别文件

2.2.4 匿名管道指令实现

 2.2.5 代码实现匿名管道(pipe()函数)

2.2.6 匿名管道读写规则

2.3 命名管道

2.3.1 命名管道(任何两个进程间通信)

2.3.2 指令实现命名管道

2.3.3 函数实现命名管道

2.3.4 命名管道的打开规则

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


一、进程间通信

1.1 通信目的

数据传输:一个进程需要将它的数据发送给另一个进程
资源共享:多个进程之间共享同样的资源。
通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变

1.2 通信发展

管道 ->> 匿名管道和命名管道
System V进程间通信(消息队列、共享内存、信号量)
POSIX进程间通信(消息队列、共享内存、信号、互斥量、条件变量、读写锁)


二、管道

2.1 管道的概念和分类

概念:我们把从一个进程连接到另一个进程的一个数据流称为一个“管道!
管道分为匿名和有名管道!管道的存在基于文件系统!

2.2 匿名管道

2.2.1 匿名管道(基于父子血缘关系)

父进程创建子进程,子进程文件描述符表同样指向父进程打开的文件!父子进程看到同一个文件内容,这样我们就实现了父子进程的通信!这个文件我们称为匿名管道!


2.2.2 匿名管道单向性

匿名管道父子进程一个只负责读,一个只负责写!两者读写剩余一个要关闭!


2.2.3 匿名管道是内存级别文件

如果我们父子进程其中一个向文件写,一个读,OS不会采取向磁盘文件写入,然后再从磁盘读取!因为这样严重影响效率!

OS可以不用open磁盘文件也能创造文件!它可以在内存中创造打开一个文件,然后让进程文件描述符数组指向它!这个文件没有名称,我们称之为匿名管道!进程结束,文件销毁!


2.2.4 匿名管道指令实现

Linux中 | 是管道指令,| 左写入,右读取!


 2.2.5 代码实现匿名管道(pipe()函数)


 


#include<iostream>
#include<unistd.h>//pipe fork
#include<stdio.h>//sprintf
//wait
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>//strlen
using namespace std;
int main()
{
    //创建单向通信的管道
    int fds[2];
    int ret=pipe(fds);
    if(ret==0)
    {
        cout<<"creat pipe success!"<<endl;
    }
    else{
        cout<<"creat pipe error!"<<endl;
        exit(-1);
    }
    //创建子进程
    pid_t id=fork();
    if(id<0)
    {
        perror("fork");
        exit(-1);
    }
    else if(id==0)
    {
        //子进程关闭读
        close(fds[0]);
        int cnt=0;
        const char* msg="我是子进程,我正在向父进程发消息...";
        while(1)
        {
            char buffer[1024];
            //向buffer写入
            sprintf(buffer,"child->parent[%d]:%s",++cnt,msg);
            //将buffer内容写入管道 !写入不带上'\0'
            write(fds[1],buffer,strlen(buffer));
            sleep(1);
            if(cnt==5)
            {
                close(fds[1]);
                break;
            }
        }
        exit(0);
    }
    else{
        //父进程关闭写
        close(fds[1]);
        char buffer[1024];
        int cnt=0;
        while(1)
        {
            //管道没有数据时,父进程在读取中处于阻塞状态,等待下一次读取
            ssize_t sz=read(fds[0],buffer,sizeof(buffer)-1);
            //测试阻塞效果展示 
            cout<<"you can see me!"<<endl;
          if(sz>0)
          {
            //读返回值不为0,继续下一次读取!
            buffer[sz]=0;//前面写入没带\0,所以要补上!
            cout<<"父进程接收信息:"<<buffer<<"   | 父进程累计读取次数:"<<++cnt<<endl;
          }
          else{
            //写关闭,读到返回值为0,退出读取!
            cout<<"子进程写端口已关闭!\n";
            break;
          }
        }
        //父进程回收子进程结果
        int status=0;
        pid_t n=waitpid(id,&status,0);
        //sig code !=0 表示子进程由信号杀掉,起因是子进程写入而父进程关闭了读取,OS回杀掉管道写入!
        cout<<"pid->"<<n<<" | sig code->"<<(status&0X7F)<<endl;
    }
    return 0;
}


2.2.6 匿名管道读写规则

①、当没有数据可读时
O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。
②、当管道满的时候
O_NONBLOCK disable: write调用阻塞,直到有进程读走数据
O_NONBLOCK enable:调用返回-1,errno值为EAGAIN
③、如果所有管道写端对应的文件描述符被关闭,则read返回0
④、如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE,进而可能导致write进程退出


2.3 命名管道

2.3.1 命名管道(任何两个进程间通信)

匿名管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。
如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。命名管道是一种特殊类型的文件

2.3.2 指令实现命名管道

mkfifo + pipe_name!


2.3.3 函数实现命名管道



//pipe.hpp
#include<iostream>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<cstring>
#include<cassert>
#define PIPE_PATH "/tmp/name_pipe"//路径+文件名 确定唯一的文件

void creat_pipe()
{
    umask(0);
    int ret=mkfifo(PIPE_PATH,0666);
    if(ret==0) std::cout<<"creat pipe success!\n"<<std::endl;
    else std::cout<<errno<<"creat pipe fail:"<<strerror(errno)<<std::endl;
}

void delete_pipe()
{
    int n=unlink(PIPE_PATH);
    assert(n==0);
    (void)n;
}


//server.cpp
#include"pipe.hpp"

int main()
{
    std::cout<<"hello server!"<<std::endl;
    //创建命名管道
    creat_pipe();
    //打开管道文件
    int rfd=open(PIPE_PATH,O_RDONLY);
    assert(rfd!=-1);//打开文件失败返回-1
    //server读取信息
    while(true)
    {
        char buffer[1024];
        ssize_t n=read(rfd,buffer,sizeof(buffer)-1);
        if(n>0)
        {
            buffer[strlen(buffer)]=0;
           std::cout<<"server get message:"<<buffer<<std::endl;
        }
        else
        {
            std::cout<<"client write has done!"<<std::endl;
            break;
        }
    }
    //关闭管道文件
    close(rfd);
    //销毁管道
    delete_pipe();
    return 0;
}

//client.cpp
#include"pipe.hpp"

int main()
{
    std::cout<<"hello client!"<<std::endl;
    //打开管道文件
    int wfd=open(PIPE_PATH,O_WRONLY|O_TRUNC);
    assert(wfd!=-1);
    while(true)
    {
        std::cout<<"client sent message to server->";
        char buffer[1024];
        fgets(buffer,sizeof(buffer),stdin);
        buffer[strlen(buffer)-1]=0;//去掉\n
        //向管道文件写入
        ssize_t n=write(wfd,buffer,strlen(buffer));
        assert(n!=-1);
        (void)n;
    }
    close(wfd);
    return 0;
}


 2.3.4 命名管道的打开规则

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

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

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

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

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

相关文章

一文讲清楚shell 中的变量是怎么回事

目录 变量和引用 一&#xff0c; 什么是变量 二&#xff0c; 根据数据类型分类 三&#xff0c; 根据作用域分类 1、环境变量 2、普通变量 四&#xff0c; 变量的定义 1、变量定义示例&#xff1a;变量名变量值 2、位置参数和预定义变量 五&#xff0c; shell中的引用 六&…

【GPLT 二阶题目集】L2-022 重排链表

输入格式&#xff1a; 每个输入包含1个测试用例。每个测试用例第1行给出第1个结点的地址和结点总个数&#xff0c;即正整数N (≤10^5 )。结点的地址是5位非负整数&#xff0c;NULL地址用−1表示。 接下来有N行&#xff0c;每行格式为&#xff1a; Address Data Next 其中Addres…

深拷贝和浅拷贝对比

JavaScript存储引用数据&#xff08;对象&#xff09;都是存地址的&#xff0c;存放在堆内存中的对象&#xff0c;在栈内存中存的是一个指针&#xff0c;这个指针指向堆内存一个位置。再从堆内存中取得所需的数据。 深拷贝&#xff1a;对数据进行拷贝之后&#xff0c;修改拷贝之…

Python:从协议到抽象基类

本章话题是接口&#xff1a;鸭子类型代表特征动态协议&#xff1b; 使接口更明确、能验证实现是否副了规定的抽象基类ABC(Abstact Base Class).Python语言诞生15年后&#xff0c;Python2.6中才引入了抽象基类&#xff0c;抽象基类。对于java、C#类似的语言&#xff0c;会觉得鸭…

DevSecOps敏捷安全技术金字塔V3.0正式发布

2022年12月28日&#xff0c;由悬镜安全主办&#xff0c;3S-Lab软件供应链安全实验室、Linux基金会OpenChain社区、ISC、OpenSCA社区联合协办的第二届全球DevSecOps敏捷安全大会&#xff08;DSO 2022&#xff09;已通过全球直播的形式圆满举行。本届大会以“共生敏捷进化”为主题…

HTB_Markup_xml注入读ssh私钥进程注入

文章目录信息收集xml注入ssh 私钥连接提权信息收集 使用如下参数可以探测具体版本&#xff0c;只使用-sV -v无此效果 nmap -sC -A -Pn 10.129.95.192是个登录页面 弱口令&#xff0c;只有admin-password成功登录 几个页面&#xff0c;只有order.php页面可以与后端交互并传递x…

【Kubernetes 企业项目实战】06、基于 Jenkins+K8s 构建 DevOps 自动化运维管理平台(中)

目录 一、基于 Jenkinsk8sGitDocker Hub 等技术链构建企业级 DevOps 容器云平台 1.1 安装 Jenkins 1.1.1 安装 nfs 服务 1.1.2 在 kubernetes 中部署 jenkins 1.2 配置 Jenkins ​1.2.1 获取管理员密码 1.2.2 安装插件 1.2.3 创建第一个管理员用户 1.3 测试 jenkins 的…

VMware Workstation中安装Kali 2022

VMware Workstation中安装Kali 2022 前言 开工了&#xff0c;笔记本中的相关工具该更新了&#xff0c;今天记录一下。 首先记录的是在VMware Workstation中安装kali&#xff0c;这个过程比较简单。 我只是想扩充一下自己的博客&#xff0c;另外可以给入门人员一个参考。 下载…

react的JSX语法

1.jsx基本使用 1 createElement() 的问题 繁琐不简洁。不直观&#xff0c;无法一眼看出所描述的结构。不优雅&#xff0c;用户体验不爽。 2 JSX 简介 JSX 是 JavaScript XML 的简写&#xff0c;表示在 JavaScript 代码中写 XML&#xff08;HTML&#xff09; 格式的代码。 优…

通信原理笔记—增量调制(∆M)

目录 概述&#xff1a; 简单增量调制(∆M)原理&#xff1a; 编码器与解码器 简单△M的过载问题&#xff1a; 增量总和(∆-Σ)调制 数字压扩自适应增量调制&#xff1a; 不同编码调制方式的误码性能分析&#xff1a; 概述&#xff1a; 最简单的DPCM是增量调制&#xff0c…

layui框架学习(4:导航)

layui官网教程采用html中的无序列表和定义列表来实现导航样式&#xff08;文章最后还有个关于导航所用元素的补充说明&#xff09;&#xff0c;主要包括水平导航、垂直/侧边导航&#xff0c;同时还支持用span和a元素实现面包屑导航样式。导航功能需要加载element模块&#xff0…

实验二:Linux主机漏洞利⽤攻击实践

&#xff08;一&#xff09;实验简介 实验所属系列&#xff1a;windows主机漏洞利用攻击实践 实验对象&#xff1a;本科/专科信息安全专业 相关课程&#xff1a;渗透测试 实验时数&#xff08;学分&#xff09;&#xff1a;2学时 实验类别&#xff1a;实践类 &#xff08;二&a…

如何集中式管理多个客户端节点传输任务-镭速

在一些生产制造企业或it部门&#xff0c;它们的生产机器设备每天都会有大量的生产数据&#xff0c;并且需要人为地对这些数据进行迁移或者归档备份到其他存储。这样重复性的操作&#xff0c;无疑大大提高了人工成本&#xff0c;而且运作起来的效率也不高。 镭速服务器集中式任务…

MySQL优化方案

一、MySQL 的优化方案有哪些&#xff1f;MySQL 数据库常见的优化手段分为三个层面&#xff1a;SQL 和索引优化、数据库结构优化、系统硬件优化等&#xff0c;每个大的方向中又包含多个小的优化点。1.SQL 和索引优化通过优化 SQL 语句以及索引来提高 MySQL 数据库的运行效率① 使…

【UE5】动画系统

title: 【UE5】动画系统 date: 2023-01-31 19:50:47 tags: UE5 categories: 学习笔记 password: abstract: message: 最近接触的项目涉及到动捕和动画&#xff0c;以前接触的范围主要是GamePlay以及C和蓝图的交互&#xff0c;很少接触动画&#xff0c;借此机会学习一下UE5的动…

【Jmeter】报错解决:JedisException: Could not return the broken resource to the pool

一、报错详情 (1)报错场景 使用 Jmeter 插件 Redis Data Set 配置连接 Redis 数据池时,运行出现报错 (2)报错日志

Python对liunx中mysql数据库进行单表查询 10个案例带你了解

关于Python连接liunx中mysql数据库的方式在这一篇文章 这里写目录标题1.在Liunx服务器中的mysql新建一个表2.插入数据3.连接liunx中的mysql数据库1、查询1946班的成绩信息2&#xff0c;查询1944班&#xff0c;语文成绩大于60小于90的成绩信息3&#xff0c;查询学生表中1到6行的…

QTabWidget 美化 qss

1. tab&#xff0c; tab-bar&#xff0c; pane属性分布 2. 使用qss美化时&#xff0c;tab标签上和pane中都能美化成功&#xff0c;但tab最右侧的tab-bar却始终没有成功。 /*设置控件的背景*/ QTabWidget {background-color:rgb(4,138,224); } /*设置控件下面板的背景颜色*/ QT…

C++11 常用的新特性

本篇介绍C11标准对比之前C标准的新特性&#xff0c;C11为C语言在2011年发布的版本&#xff0c;它改进幅度很大&#xff0c;影响至今。如加入auto 关键字、nullptr、移动语义&#xff08;move semantics&#xff09;、委托构造函数&#xff08;delegating constructors&#xff…

ChatGPT超详细注册与使用教程

文章目录前言一、ChatGPT账号注册二、SMS-ACTIVATE虚拟手机号验证三、ChatGPT使用总结前言 最近ChatGPT非常火爆&#xff0c;是一种革命性的技术&#xff0c;这也吸引来了很多人想尝试一下&#xff0c;但是由于并没有在国内开通这项服务&#xff0c;所以国内的用户无法使用Chat…