Linux利用管道通信实现一个写端对应多个读端(二)

简介: Linux利用管道通信实现一个写端对应多个读端(二)

命名管道

实现目的

实现一个写端进程负责发送数据,运行多个读端进程,并且写端进程与每个读端进程都有独立的命名管道

写端进程可以随机向某个管道中写入数据后,管道对应的读端将数据读取输出

思路

  1. 编写一个头文件,定义所有需要创建的命名管道的文件名,并将所有文件名集合到一个数组中
  2. 定义创建命名管道文件的函数
  3. 定义删除明明管道文件的函数
  4. 编写写端程序,一次性在当前目录下将所有的命名管道文件创建,并记录所有命名管道的fd到一个数组中,将所有管道文件打开
  5. 编写向管道文件中写入的方法,首先先将写入的字符串保存,随机生成一个下标,知道到该下标对应的fd,并往该fd对应的管道文件中写入
  6. 编写全部读端程序,每个读端程序对应一个管道文件,并将管道文件打开
  7. 编写读端读取数据的方法
  8. 在每一个读端程序中加入删除管道文件的步骤,当写端退出时,读端也会随着退出,退出关闭fd后将管道文件删除
  9. 需要注意,以下代码示例为写端创建管道文件,因此要先运行写端程序。

NAME_PIPE.hpp

#include<iostream>
#include<unistd.h>
#include<string>
#include<cstring>
#include<sys/types.h>
#include<sys/stat.h>
#include<cassert>
#include<errno.h>
#include<vector>
#include<fcntl.h>
#include<ctime>
//宏定义管道名字
#define NAME_PIPE_1 "./NAME_PIPE_1"
#define NAME_PIPE_2 "./NAME_PIPE_2"
#define NAME_PIPE_3 "./NAME_PIPE_3"
#define NAME_PIPE_4 "./NAME_PIPE_4"
//将管道名字保存
std::vector<std::string> NameGroup({NAME_PIPE_1, NAME_PIPE_2, NAME_PIPE_3, NAME_PIPE_4});
//创建管道函数
bool CreatPipe(const std::string& path){
    umask(0);
    int n = mkfifo(path.c_str(), 0666);
    if(n == 0)
        return true;
    else{
        std::cout << "管道创建失败:" << strerror(errno) << std::endl;
        return false;
    }
}
//删除管道函数
void RemovePipe(const std::string& path){
    assert(unlink(path.c_str()) == 0);
}

WProc.cc

#include"NAME_PIPE.hpp"
int main(){
    srand(time(nullptr));
    std::vector<int> Fdgroup;
  //创建所有的管道文件
    for(int i = 0; i < NameGroup.size(); ++i)
        assert(CreatPipe(NameGroup[i]));
  //打开所有的管道文件,并将所有的管道文件fd保存
    for(int i = 0; i < NameGroup.size(); ++i){
        int fd = open(NameGroup[i].c_str(), O_WRONLY);
        if(fd < 0)
            return 1;
        Fdgroup.push_back(fd);
    }
    std::string str;
    while(1){
      //随机生成一个下标,往该下标的管道文件中写入
        int i = rand() % Fdgroup.size();
        std::cout << "开始写入:";
        getline(std::cin, str);
        int s = write(Fdgroup[i], str.c_str(), strlen(str.c_str()));
    }
  //关闭所有管道文件
    for(int i = 0; i < Fdgroup.size(); ++i)
        close(Fdgroup[i]);
    return 0;
}

RProc1.cc

#include"NAME_PIPE.hpp"
int main(){
  //打开管道文件只读
    int fd = open(NAME_PIPE_1, O_RDONLY);
    assert(fd > 0);
  //阻塞着随时等待管道文件中有数据,一有数据立刻读取
    while(1){
        char buff[1024];
        int s = read(fd, buff, sizeof(buff) - 1);
        if(s > 0)
            buff[s] = 0;
        else
            break;
        std::cout << "RProc1 read : " << buff << std::endl;
    }
    close(fd);
  //删除对应的管道文件
    RemovePipe(NAME_PIPE_1);
    return 0;
}

RProc2.cc

#include"NAME_PIPE.hpp"
int main(){
    int fd = open(NAME_PIPE_2, O_RDONLY);
    assert(fd > 0);
    while(1){
        char buff[1024];
        int s = read(fd, buff, sizeof(buff) - 1);
        if(s > 0)
            buff[s] = 0;
        else
            break;
        std::cout << "RProc2 read : " << buff << std::endl;
    }
    close(fd);
    RemovePipe(NAME_PIPE_2);
    return 0;
}

RProc3.cc

#include"NAME_PIPE.hpp"
int main(){
    int fd = open(NAME_PIPE_3, O_RDONLY);
    assert(fd > 0);
    while(1){
        char buff[1024];
        int s = read(fd, buff, sizeof(buff) - 1);
        if(s > 0)
            buff[s] = 0;
        else
            break;
        std::cout << "RProc3 read : " << buff << std::endl;
    }
    close(fd);
    RemovePipe(NAME_PIPE_3);
    return 0;
}

RProc4.cc

#include"NAME_PIPE.hpp"
int main(){
    int fd = open(NAME_PIPE_4, O_RDONLY);
    assert(fd > 0);
    while(1){
        char buff[1024];
        int s = read(fd, buff, sizeof(buff) - 1);
        if(s > 0)
            buff[s] = 0;
        else
            break;
        std::cout << "RProc4 read : " << buff << std::endl;
    }
    close(fd);
    RemovePipe(NAME_PIPE_4);
    return 0;
}

动图结果演示


ab7ea2b1c6fd45e7830298f02152061a.gif

相关实践学习
CentOS 7迁移Anolis OS 7
龙蜥操作系统Anolis OS的体验。Anolis OS 7生态上和依赖管理上保持跟CentOS 7.x兼容,一键式迁移脚本centos2anolis.py。本文为您介绍如何通过AOMS迁移工具实现CentOS 7.x到Anolis OS 7的迁移。
目录
相关文章
|
1月前
|
消息中间件 Linux 开发者
Linux进程间通信秘籍:管道、消息队列、信号量,一文让你彻底解锁!
【8月更文挑战第25天】本文概述了Linux系统中常用的五种进程间通信(IPC)模式:管道、消息队列、信号量、共享内存与套接字。通过示例代码展示了每种模式的应用场景。了解这些IPC机制及其特点有助于开发者根据具体需求选择合适的通信方式,促进多进程间的高效协作。
67 3
|
1月前
|
存储 Unix Linux
Linux I/O 重定向与管道
【8月更文挑战第17天】重定向在Linux中改变命令I/O流向,默认有&quot;&gt;&quot;覆盖输出至文件及&quot;&gt;&gt;&quot;追加输出至文件末尾,便于保存结果;使用&quot;&lt;&quot;从文件读取输入而非键盘,高效处理数据。文件描述符如0(stdin)、1(stdout)、2(stderr)标识I/O资源,支持读写操作。管道以&quot;|&quot;连接命令,使前一命令输出成为后一命令输入,如排序用户或找出CPU占用最高的进程,构建复杂数据处理流程。
38 9
|
1月前
|
存储 Linux 数据处理
在Linux中,什么是管道操作,以及如何使用它?
在Linux中,什么是管道操作,以及如何使用它?
|
1月前
|
Linux
Linux源码阅读笔记13-进程通信组件中
Linux源码阅读笔记13-进程通信组件中
|
1月前
|
消息中间件 安全 Java
Linux源码阅读笔记13-进程通信组件上
Linux源码阅读笔记13-进程通信组件上
|
1月前
|
存储 Unix Linux
Linux I/O 重定向与管道
【8月更文挑战第14天】输出重定向可将命令结果存入文件,如`&gt;`覆盖写入或`&gt;&gt;`追加写入。输入重定向从文件读取数据,如`&lt;`代替键盘输入。这些操作利用文件描述符(如0:stdin, 1:stdout, 2:stderr)管理I/O。管道`|`连接命令,使前一命令输出作为后一命令输入,便于数据处理,如排序用户`sort -t: -k3 -n /etc/passwd | head -3`或查找CPU占用高的进程`ps aux --sort=-%cpu | head -6`。
23 4
|
27天前
|
开发者 API Windows
从怀旧到革新:看WinForms如何在保持向后兼容性的前提下,借助.NET新平台的力量实现自我进化与应用现代化,让经典桌面应用焕发第二春——我们的WinForms应用转型之路深度剖析
【8月更文挑战第31天】在Windows桌面应用开发中,Windows Forms(WinForms)依然是许多开发者的首选。尽管.NET Framework已演进至.NET 5 及更高版本,WinForms 仍作为核心组件保留,支持现有代码库的同时引入新特性。开发者可将项目迁移至.NET Core,享受性能提升和跨平台能力。迁移时需注意API变更,确保应用平稳过渡。通过自定义样式或第三方控件库,还可增强视觉效果。结合.NET新功能,WinForms 应用不仅能延续既有投资,还能焕发新生。 示例代码展示了如何在.NET Core中创建包含按钮和标签的基本窗口,实现简单的用户交互。
49 0
|
1月前
|
消息中间件 Linux
Linux0.11 管道(十一)
Linux0.11 管道(十一)
17 0
|
1月前
|
数据挖掘 Linux 应用服务中间件
在Linux中,如何在Linux中使用管道?
在Linux中,如何在Linux中使用管道?
|
1月前
|
存储 Linux 数据处理
在Linux中,管道(pipe)和重定向(redirection)的是什么?
在Linux中,管道(pipe)和重定向(redirection)的是什么?