进程通信管道制作

news2024/12/24 8:23:56

利用父子进程

创建管道利用pipe函数

// 1.创建管道
    int pipefd[2] = {0}; //[0] 读端  ,[1]写端
    int n = pipe(pipefd);
    assert(n != -1); // debug 在release下会裁减
    (void)n;//防止在release下报错
    cout << "fd[0]:" << pipefd[0] << endl; // 3
    cout << "fd[1]:" << pipefd[1] << endl; // 4

pipe该函数内会创建一个管道文件,我们需要手动传入一个整型数组保存两个元素。

当函数返回继续检查。注意我们的pipefd[0]为对管道读端,pipe[1]为对管道写端,保存的是文件描述符fd。

    pid_t id = fork();
    assert(id != -1);
    //父进程写入,子进程读取
    if (id == 0)
    {
        //子进程
        //构建单项通信
        int end=0;
        close(pipefd[1]); //关闭子进程prpefd[1]。
        //char buff[1024];
        while (1)
        {
            //子进程工作
        }
        close(pipefd[0]);
        exit(0);
    }

fork()创建子进程通过id判断是否为子进程,如果是0子进程就进入 if 判断式。

子进程继承父进程的进程一众数据结构,那么files_struct也是一样的,所以我们通过fd也可以访问文件。子进程读取数据,就要将写端关闭(也可不关),close(pipefd[1]);然后进行通信工作。

结束后关闭读端,然后结束子进程。

    // 父进程
    //构建单项通信
    close(pipefd[0]);
    char send_buff[1024 ];
    while (1)
    {
      //父进程写入工作
    }
    //工作结束
    close(pipefd[1]);
    //回收子进程
    pid_t ret = waitpid(id, nullptr, 0);
    assert(ret != -1);
    return 0;
}

父进程关闭读端(也可以不关闭),创建缓冲区,进行写入工作,当工作结束关闭对管道的写端。

然后等待子进程结束回收资源。判断是否正确回收。结束进程。

有一些情况:管道文件,提供了协同工作的机理。读写同步。

写段关闭,读端进程会读取到文件结尾,退出循环。

读端关闭,写端进程被操作系统强行嗝屁。(子进程变为孤儿进程)。

完整代码

#include <iostream>
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <assert.h>
#include <string>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;

int main()
{
    // 1.创建管道
    int pipefd[2] = {0}; //[0] 读端  ,[1]写端
    int n = pipe(pipefd);
    assert(n != -1); // debug 在release下会裁减
    (void)n;
#ifdef DEBUG
    cout << "fd[0]:" << pipefd[0] << endl; // 3
    cout << "fd[1]:" << pipefd[1] << endl; // 4
#endif
    pid_t id = fork();
    assert(id != -1);
    //父进程写入,子进程读取
    if (id == 0)
    {
        //子进程
        //构建单项通信
        int end=0;
        close(pipefd[1]); //关闭子进程prpefd[1]。
        char buff[1024];
        while (1)
        {
            ssize_t s = read(pipefd[0], buff, sizeof(buff) - 1);
            if (s > 0)
            {
                buff[s] = '\0';
                cout << "child:pid[" << getpid() << "]father#" << buff << endl;
            }
            else if (s == 0)
            {
                printf("写入方关闭写端\n");
                break;
            }
            cout<<"end:"<<end<<endl;
            if(end++==5)
            {
                cout<<"写端提前关闭"<<endl;
                break;
            }
        }
        cout<<"子进程关闭读端"<<endl;
        close(pipefd[0]);
        // close(pipefd[0]);
        exit(0);
    }
    // 父进程
    //构建单项通信
    close(pipefd[0]);
    string parent("我是父进程!!!我在发信息");
    int cnt = 0;
    char send_buff[1024];

    while (1)
    {
        memset(send_buff,0,sizeof(send_buff));
        snprintf(send_buff, sizeof(send_buff), "%s[%d次]:ppid=%d", parent.c_str(), cnt++, getpid());
        // 3.3写入管道
        sleep(1);
        int m = write(pipefd[1], send_buff, strlen(send_buff));
        cout << cnt << endl;
        if (m < 0)
        {
            printf("写入失败\n");
        }
        sleep(1);
    }
    printf("父进程关闭写端\n");
    close(pipefd[1]);
    sleep(10);
    pid_t ret = waitpid(id, nullptr, 0);
    assert(ret != -1);

    return 0;
}

非父子进程管道通信。

创建两个进程,通过管道进行通信链接。

首先先介绍,mkfifo函数,显示的创建一个管道文件,

int mkfifo(const char *pathname, mode_t mode);

pathname:创建管道的文件名字以及路径。

mode:管道文件权限设置。

我们的两个进程需要同时访问同一个管道文件,所以我们创建的路径一定要一致。我们让两个源代码使用同一头文件。

//pipe.hpp
#ifndef _COMM_H_
#define  _COMM_H_
#include<cstdio>
#include<cstring>
#include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include"Log.hpp"
#define MODE 0666
#define SIZE 128
using namespace std;
string ipcPath("./fifi.ipc");//可绝对可相对,为了简便我们使用相对路径
#endif

创建一个string 类,管道文件保存路径,两个包含该头文件的源代码就可以访问到相同的管道文件了。

我们在读取数据方创建管道文件(也可以在发送数据方)

int main()
{
    //创建管道
    if(mkfifo(ipcPath.c_str(),MODE)<0)
    {
        perror("mkfifo fail!\n");
        exit(-1);
    }
    Log("管道创建成功",Debug)<<"stap 1"<<endl;//日志信息

创建管道,会在当前目录下生成,管道文件

 当前进程链接管道。

 //链接管道
    int fd=open(ipcPath.c_str(),O_RDONLY);
    if(fd==-1)
    {
        perror("open");
        exit(-2);
    }
    Log("管道打开成功",Debug)<<"stap 2"<<endl;//日志信息

如果管道写端没有被访问,会在管道内阻塞读端进程

写端进程运行 

读端停止阻塞,继续运行。

 //使用管道开始通信
    char buffer[SIZE];
    while(1)
    {
        memset(buffer,0,sizeof(buffer));
        ssize_t s=read(fd,buffer,sizeof(buffer)-1);
        if(s>0)
        {
            buffer[s]='\0';
            cout<<buffer<<endl;
        }
        else if(s==0)
        {
            printf("file read end,end receive colse\n");
            break;
        }
        else
        {
            printf("read error!!!\n");
            exit(-3);
        }
    }

开始读取工作。

当我们关闭写端。

 close(fd);
    Log("管道关闭成功",Debug)<<"stap 3"<<endl;
    unlink(ipcPath.c_str());
    Log("管道删除成功",Debug)<<"stap 4"<<endl;
    return 0;
}

我们先关闭fd文件描述符,在删除管道文件。

读端完整代码

#include"commt.hpp"

int main()
{
    //创建管道
    if(mkfifo(ipcPath.c_str(),MODE)<0)
    {
        perror("mkfifo fail!\n");
        exit(-1);
    }
    Log("管道创建成功",Debug)<<"stap 1"<<endl;
    //链接管道
    int fd=open(ipcPath.c_str(),O_RDONLY);
    if(fd==-1)
    {
        perror("open");
        exit(-2);
    }
    Log("管道打开成功",Debug)<<"stap 2"<<endl;

    //使用管道开始通信
    char buffer[SIZE];
    while(1)
    {
        memset(buffer,0,sizeof(buffer));
        ssize_t s=read(fd,buffer,sizeof(buffer)-1);
        if(s>0)
        {
            buffer[s]='\0';
            cout<<buffer<<endl;
        }
        else if(s==0)
        {
            printf("file read end,end receive colse\n");
            break;
        }
        else
        {
            printf("read error!!!\n");
            exit(-3);
        }
    }
    close(fd);
    Log("管道关闭成功",Debug)<<"stap 3"<<endl;
    unlink(ipcPath.c_str());
    Log("管道删除成功",Debug)<<"stap 4"<<endl;
    return 0;
}


相比读端我们的写端代码量轻松的多。

#include"commt.hpp"

int main()
{
    //打开管道
    int fd=open(ipcPath.c_str(),O_WRONLY);
    if(fd<-1)
    {
        perror("open fail!\n");
        exit(-1);
    }
    string buffer;
    while(1)
    {
        cout<<"Plase Enter Message Line >";
        std::getline(std::cin,buffer);
        write(fd,buffer.c_str(),buffer.size());
    }
    close(fd);
    return 0;
}

 写端只需要普通的文件操作,要注意的是需要打开同一个管道文件,进行写入。在运行结束的时候关闭fd即可,删除管道文件在读端进程完成。

 

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

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

相关文章

多用户商城开源-多店铺商城系统平台开发

多用户商城开源是指一种基于开放源代码的电子商务平台&#xff0c;允许多个用户共享一个平台&#xff0c;每位用户可以创建自己的电子商城&#xff0c;并在平台上进行交易、管理、营销等操作。多用户商城开源通常包含多种功能&#xff0c;如商品管理、订单管理、支付集成、促销…

vue diff算法与虚拟dom知识整理(14) patchVNode处理子节点新增和删减

上文 vue diff算法与虚拟dom知识整理(13) 手写patch子节点更新换位策略 我们实现了子节点位置的更新策略 但还有一些匹配不到的情况会导致死循环 那么我们继续来优化一下 我们先将src下的 index.js 代码改成这样 import h from "./snabbdom/h"; import patch from …

Scrapy ImagesPipeline下载图片

一、 ImagesPipeline是啥 ImagesPipeline是scrapy自带的类&#xff0c;用来处理图片(爬取时将图片下载到本地)。 二、ImagesPipeline优势&#xff1a; 将下载图片转换成通用的jpg和rgb格式避免重复下载缩略图生成图片大小过滤异步下载 三、ImagesPipeline工作流程 爬取一个…

Echarts构建指定省份的地图

1. 自行准备好Echarts环境 Echarts官网&#xff1a;https://echarts.apache.org/zh/index.html 2. 下载需要的省份或者城市的json地理信息文件 下载我们需要显示地区的Json数据&#xff0c;这个Json数据用于Echart的地图显示 例如我这里是下载的&#xff1a;湖南、湖北、四川…

同步模式之顺序控制线程执行

tip: 作为程序员一定学习编程之道&#xff0c;一定要对代码的编写有追求&#xff0c;不能实现就完事了。我们应该让自己写的代码更加优雅&#xff0c;即使这会费时费力。 文章目录 一、同步模式之顺序控制线程执行二、代码样例三、三个线程分别输出a、b、c&#xff0c;按顺序输…

作为一个项目管理成员,怎样才能有效监控项目执行?

作为一个项目管理成员&#xff0c;有效监控项目执行是确保项目成功的关键。在项目执行期间&#xff0c;您需要密切关注项目进展&#xff0c;并及时采取行动来纠正任何偏差。以下是几个有效的方法&#xff0c;可以帮助您监控项目执行并确保项目按计划顺利进行。 1. 制定详细的项…

C语言进阶--数据的存储

目录 数据类型介绍 基本内置类型&#xff1a; 类型的意义&#xff1a; 类型的基本归纳&#xff1a; 整型在内存中的存储 原码&#xff0c;反码和补码&#xff1a; 大小端存储模式&#xff1a; 大小端产生原因&#xff1a; 浮点型在内存中的存储 数据类型介绍 基本内…

六、机械手的种类

机械手是机器人能够完成指令的一个重要输出装置&#xff0c;机器臂是否合理、有效&#xff0c;决定了机 器人能否发挥出应有的作用。 机械手是一种能模仿人手和臂的某些动作功能&#xff0c;用以按固定程序抓取、搬运物件或操作工具的自动操作装置。特点是可以通过编程来完成各…

wy的leetcode刷题记录_Day68

wy的leetcode刷题记录_Day68 声明 本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间&#xff1a;2023-6-6 前言 目录 wy的leetcode刷题记录_Day68声明前言1019. 链表中的下一个更大节点题目介绍思路代码收获 1019. 链表中的下一个更大节点 2352. 相等行列…

CPU、内存、缓存的关系

术语解释 &#xff08;1&#xff09;CPU&#xff08;Central Processing Unit&#xff09; 中央处理器 &#xff08;2&#xff09;内存 内存用于暂时存放CPU中的运算数据&#xff0c;以及与硬盘等外部存储器交换的数据。它是外存与CPU进行沟通的桥梁&#xff0c;内存的运行决定…

Docker容器管理

docker容器相当于一个进程&#xff0c;性能接近于原生&#xff0c;几乎没有损耗&#xff1b; docker容器在单台主机上支持的数量成百上千&#xff1b; 容器与容器之间相互隔离&#xff1b; 镜像是创建容器的基础&#xff0c;可以理解镜像为一个压缩包 docker容器的管理 容…

深耕电力行业,百度智能云助力电厂节煤降耗

山西省吕梁市汾阳市三泉镇&#xff0c;晋能集团旗下山西国峰煤电有限责任公司的两台300MW循环流化床直接空冷机组正在运行&#xff0c;燃煤通过传送带进入锅炉燃烧&#xff0c;将水加热成高温高压蒸汽&#xff0c;用以推动汽轮机拖动发电机旋转发电&#xff0c;支撑工业生产、点…

CW32-Template CW32F030开发板工程模板

国产MCU Embedded-CW32-Board-Template Embedded-CW32-Board-Template CW32-Template第三方资源集合 CW-Template CW32开发者开发板资料 CW32-Board 开发板资料 合集 官方提供的案例Examples CW32F030_StandardPeripheralLib\Examples CW32-48F大学计划板例程 EX1流…

优思学院|精益和六西格玛都强调的一件东西...

精益和六西格玛有着诸多不同&#xff0c;它们的方法和理念也不尽相同&#xff0c;但却有一件东西&#xff0c;是他们的共同理念和工具&#xff0c;那就是----标准。 标准&#xff0c;是企业管理中至关重要的一环。标准&#xff0c;不仅指导着我们对人、物和流程的处理方式&…

2023年鄂州中级职称水测考试什么时候考试?

今天鄂州中级职称水测考试开始打印准考证了&#xff0c;但是只能打印部分专业的水测准考证&#xff0c;按照专业&#xff0c;按照批次打印的。 具体通知如下: 各位考生&#xff1a; 为积极稳妥做好我市晋升中、初级专业技术职称综合系列水平能力测试工作&#xff0c;现按专业分…

【2023 年第十三届 MathorCup 高校数学建模挑战赛】A 题 量子计算机在信用评分卡组合优化中的应用 37页论文及代码

相关信息 &#xff08;1&#xff09;建模思路 【2023 年第十三届 MathorCup 高校数学建模挑战赛】A 题 量子计算机在信用评分卡组合优化中的应用 详细建模过程解析及代码实现 【2023 年第十三届 MathorCup 高校数学建模挑战赛】 B 题 城市轨道交通列车时刻表优化问题 详细建…

2023BR软件、Adobe Bridge下载、安装教程

最后附下载地址 Adobe Bridge CS5 软件是一款功能强大的媒体管理器&#xff0c;它允许您集中访问所有创作资源。 功能介绍 1、可以方便地访问本地PSD、AI、INDD 和 Adobe PDF 文件以及其它 Adobe 和非 Adobe 应用程序文件。 2、可以将资源按照需要拖移到版面中进行预览&…

安卓平台下的即时通讯技术深入解析【实时聊天应用开发实战】

摘要: 本文将详细介绍如何使用安卓开发技术实现一个实时聊天应用。我们将通过构建一个基于安卓平台的聊天应用,演示如何处理用户注册、登录、消息发送和接收等关键功能。文章将涵盖安卓开发的各个方面,包括用户界面设计、后端服务器搭建、网络通信、数据存储和安全性等。读…

spring6

Spring6 1、概述 1.1、Spring是什么&#xff1f; Spring 是一款主流的 Java EE 轻量级开源框架 &#xff0c;Spring 由“Spring 之父”Rod Johnson 提出并创立&#xff0c;其目的是用于简化 Java 企业级应用的开发难度和开发周期。Spring的用途不仅限于服务器端的 开发。从简…

【Mysql数据库从0到1】-入门基础篇--数据库了解

【Mysql数据库从0到1】-入门基础篇--数据库了解 &#x1f53b;一、数据库产生背景&#x1f53b;二、数据库有关概述&#x1f53b;三、数据库访问接口&#x1f53b;四、数据库种类&#x1f53b;五、数据库有关术语&#x1f53b;六、常见DBMS排名&#x1f53b;七、常见数据库介绍…