【Linux】 管道扩展 — 开始使用命名管道

news2024/11/16 19:55:21

在这里插入图片描述

送给大家一句话:
人生有六个字,前面三个是不害怕,后面三个是不后悔。 -- 董卿
🔆🔆🔆🔆🔆🔆🔆🔆

命名管道的功能实现

  • 1 命名管道的原理
  • 2 代码实现
    • 2.1 系统调用
    • 2.2 命名管道的封装
    • 2.3 开始使用
  • 3回归概念
  • Thanks♪(・ω・)ノ谢谢阅读!!!
  • 下一篇文章见!!!

1 命名管道的原理

命名管道时进程间通信的一种,那么原理也就是类似的:先让不同的进程看到同一份(操作系统)资源(“一段内存”)。

匿名管道是通过父子进程的继承关系来满足:父子进程可以看到同一段内存!这段内存会在子进程创建时的拷贝一份,所以并不需要名字,只需要通过pipefd[0] pipefd[1]来记录其读写端的文件描述符,然后在父子进程中关闭对应的文件描述符,达到单方向通信的需求!
在这里插入图片描述
根据匿名管道的底层,两个毫不相干的进程就无法通过匿名管道的方式来进行通信

那么两个毫不相干的进程如何才能看的同一片内存,才能共享一个文件缓冲区呢?当然就通过文件的路径(唯一性)来打开!

当两个进程打开同一个文件时,他们共享该文件的内核缓冲区。为了我们的通信效率,肯定不能把缓冲区的数据刷新到硬盘中。所以这个文件必须是一个特殊的文件,只用于通信的需求!!!

这个文件就是命名管道!!!

2 代码实现

2.1 系统调用

匿名管道的创建是通过系统调用:pipe(int pipefd[2]) 来建立,同样命名管道的创建也有对应的指令:mkfifo

MKFIFO(1)                                                                 User Commands                                                                MKFIFO(1)

NAME
       mkfifo - make FIFOs (named pipes)

SYNOPSIS
       mkfifo [OPTION]... NAME...

DESCRIPTION
       Create named pipes (FIFOs) with the given NAMEs.

       Mandatory arguments to long options are mandatory for short options too.

       -m, --mode=MODE
              set file permission bits to MODE, not a=rw - umask

       -Z     set the SELinux security context to default type

       --context[=CTX]
              like -Z, or if CTX is specified then set the SELinux or SMACK security context to CTX

       --help display this help and exit

       --version
              output version information and exit

我们使用一下来看看:
在这里插入图片描述
这个文件类型是p不同于-(普通文件)和d(目录),p表示管道文件,显然它是有名字的!
我们来尝试通信一下:
在这里插入图片描述
此时两个不同的进程就可以进行通信!!!
我们在让两个进程保持一直通信的状态,这样读端可以一直获取数据!
在这里插入图片描述

当我们突然关闭右侧读端时,左边的写端就直接退出来了!这是因为当读端退出了,操作系统会自动释放写端进程,操作系统不会做无用功(不会在一个没有读取的管道文件了一直写入)

当然这样的通信也就只能用来演示,我们先要通过命名管道来使我们创建的两个毫不相干的进程完成通信工作,接下来我们就来实现!

2.2 命名管道的封装

首先我们来认识一下创建管道的系统调用:

MKFIFO(3)                                                           Linux Programmer's Manual                                                          MKFIFO(3)

NAME
       mkfifo, mkfifoat - make a FIFO special file (a named pipe)

SYNOPSIS
       #include <sys/types.h>
       #include <sys/stat.h>

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

       #include <fcntl.h>           /* Definition of AT_* constants */
       #include <sys/stat.h>

       int mkfifoat(int dirfd, const char *pathname, mode_t mode);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       mkfifoat():
           Since glibc 2.10:
               _POSIX_C_SOURCE >= 200809L
           Before glibc 2.10:
               _ATFILE_SOURCE

int mkfifo(const char *pathname, mode_t mode);
第一个参数const char *pathname 是要建立的管道文件的路径与文件名,第二个参数mode_t mode 表示文件权限

返回值的意义:

ETURN VALUE
On success mkfifo() and mkfifoat() return 0. In the case of an error, -1 is returned (in which case, errno is set appropriately).
创建成功返回 0 失败返回 -1!

通过这些我可以先搭建一个基础类,可以创建管道文件!

  • 成员

    1. 管道文件名 const std::string _fifo_path
    2. 文件描述符 _fd 默认为-1
    3. 操作者类型 _id 1 /2
  • 构造函数 --> 创建管道 CreateNamePipe(const std::string &path )
    使用函数 int mkfifo(const char *pathname, mode_t mode); 文件名为 path(需要确定下来 保证引用该头文件的都可以获取) 权限为0666
    为 0 正常建立 , 为 -1 建立失败 测试创建是否成功

  • 析构函数 --> 删除管道 RemoveNamedPipe(const std::string &path )
    使用unlink(path.c_str()) 删除管道

#pragma once

#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <cstdio>
#include <unistd.h>
//文件名
const std::string path = "./myfifo";
//管道类
class NamedPipe
{
public:
    NamedPipe(const std::string fifo_path)
        : _fifo_path(fifo_path)
    {
        int n = mkfifo(_fifo_path.c_str(), 0666);
        if(n != 0)
        {
            perror("mkfifo");
        }

    }
    ~NamedPipe()
    {
        sleep(10);
        unlink(_fifo_path.c_str());
    }

private:
    const std::string _fifo_path;
    int _fd;
    int _id;
};

这样就可以通过类的实例化对象来建立管道!!!

接下来我们进行打开文件函数的书写:

  1. 首先,命名管道是文件,打开文件需要open接口,管理管道由操作者来控制。使用者只能使用不能管理管道的创建与关闭

  2. 表明身份的宏定义:----- 权限不同

    • greater 1 创建者 :只有创建者才可以建立删除管道
    • user 2 使用者 :只需要初始化其管道,不需要再建立
  3. 打开管道 OpenForRead / OpenForWrite —> OpenNamedPipe()
    打开管道的本质就是打开文件 _fd = open()
    注意打开的方式与操作者的类型紧密相关 所以进行飞封装!通过内部传参来保证权限的正确

private:
    bool OpenNamedPipe(int mode)
    {
        //sleep(2);
        std::cout << "OpenNamedPipe : " ;
        _fd = open(_fifo_path.c_str(), mode);
        if (_fd < 0)
        {
            std::cout << "false" << std::endl;
            return false;
        }
        std::cout << "true" << std::endl;
        return true;
    }
public:
// 打开文件
    int OpenForRead()
    {
        return OpenNamedPipe(Read);
    }
    int OpenForWrite()
    {
        return OpenNamedPipe(Write);
    }

打开文件之后就是进行读取或者写入,我们在写一下相应的函数:

  • 读取 ReadNamedPipe(std::string *out)
    设置缓冲区
    从管道里读取 向缓冲区写入数据
    命名管道对于读端而言 , 如果我们打开文件,但是写端还没有,就会阻塞在open调用中,等待写端进入

  • 写入 WriteNamedPipe(const std::string& in)
    向文件描述符里面进行写入

 	// 读取文件
    int ReadNamedPipe(std::string *out)
    {
        char buffer[128];
        int n = read(_fd, buffer, sizeof(buffer));
        buffer[n] = 0;
        *out = buffer;
        return n;
    }
    // 写入文件
    int WriteNamedPipe(const std::string &in)
    {
        int n = write(_fd, in.c_str(), in.size());

        return n;
    }

这样我们的封装就完成了,NamedPipe具有以下功能:

  1. 通过文件路径和操作者权限建立实例化对象
  2. 按照需求调用:OpenForRead() / OpenForWrite()打开文件
  3. 进行写入和读取WriteNamedPipe / ReadNamedPipe

2.3 开始使用

模拟客户端和服务器的通信过程:客户端写入数据,服务器读取数据

client.cc
#include"namedPipe.hpp"

int main()
{
    NamedPipe fifo(path , user);
    if(fifo.OpenForWrite())
    {
        std::cout << "client open named pipe done" << std::endl;
        while(true)
        {
            std::cout << "Please Enter>" ;
            std::string in ;
            getline(std::cin , in);
            fifo.WriteNamedPipe(in);
        }
    }
    return 0;
}
server.cc
#include"namedPipe.hpp"

int main()
{
    NamedPipe fifo(path , greater);
    //服务端进行读取
    if(fifo.OpenForRead())
    {
        std::cout << "server open named pipe done" << std::endl;
        sleep(3);
        while(true)
        {
            std::string out ;
            int n = fifo.ReadNamedPipe(&out);
            if(n > 0)
            {
                std::cout << "client say >" << out << std::endl;
            }
            else if (n == 0)
            {
                std::cout << "client quit , server too!" << out << std::endl;
                break;
            }
            else
            {
                perror("Write");
                break;
            }
        }
    }

    return 0;
}
来看效果:

在这里插入图片描述
这个效果很好玩呢!!!

注意:

  1. 对于读端来说,如果我们打开文件,但是写端还没有进入,那么就会阻塞在open()调用中!直到写端打开—进程同步!!!
  2. 当读端退出时,写端再次写入数据时会直接退出!操作系统不会做无用功!!!(直接把broken pipe坏的管道 进行杀掉!会发送对应的13号信号SIGPIPE
  3. 管道别写满 && read fd 不读且没有关闭 :
    管道被写满,写进程会被阻塞,写条件不具备-- wait 等待条件具备(读取走一部分数据才能继续写)
  4. 如果管道内部是空的 && write fd没有关闭:
    读取条件不具备,读取进程会被阻塞 – wait 等待条件具备(写入了数据)

3回归概念

总结一下,命名管道的通信原理依然是:让两个不同的进程看到同一份资源(通过文件路径)

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

Thanks♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!

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

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

相关文章

佳能R6M2断电覆盖的恢复方法

佳能R6是佳能R系列中的一款高端机&#xff0c;最近两年佳能和索尼不断斗法&#xff0c;都号称自己的新机型能达到影视级&#xff0c;不过目前看貌似索尼更胜一筹。下边这个案例是文件拍摄时断电&#xff0c;结果变成0字节&#xff0c;然后覆盖了部分数据。 故障存储:128G存储卡…

CentOS7部署Yearning并配置MySQL数据库远程访问详细流程——“cpolar内网穿透”

文章目录 前言1. Linux 部署Yearning2. 本地访问Yearning3. Linux 安装cpolar4. 配置Yearning公网访问地址5. 公网远程访问Yearning管理界面6. 固定Yearning公网地址 前言 本文主要介绍在 Linux 系统简单部署 Yearning 并结合 cpolar 内网穿透工具实现远程访问&#xff0c;破除…

都在说的跨网文件共享系统是什么?企业该怎么甄选?

跨网文件共享系统成为越来越受关注的产品焦点&#xff0c;那么跨网文件共享系统是什么呢&#xff1f;跨网文件共享是指在不同网络之间共享文件的过程&#xff0c;使得不同网络中的用户可以访问和使用共享的文件。 原则上而言&#xff0c;不同网络间的文件是无法共享的&#xff…

家政预约小程序09小程序分享及海报分享

目录 1 设置弹窗2 制作海报总结 上一篇我们介绍了服务详情页面的开发&#xff0c;本篇介绍一下用户分享及海报分享的功能 1 设置弹窗 当用户点击分享按钮的时候&#xff0c;系统弹出弹窗界面&#xff0c;提供分享好友及分享海报的选项。选中页面组件&#xff0c;添加弹窗组件 …

ReDos攻击浅析

DOS为拒绝服务攻击&#xff0c;re则是由于正则表达式使用不当&#xff0c;陷入正则引擎的回溯陷阱导致服务崩溃&#xff0c;大量消耗后台性能 正则 ​ 探讨redos攻击之前&#xff0c;首先了解下正则的一些知识 执行过程 大体的执行过程分为: 编译 -> 执行编译过程中&…

ROS2从入门到精通2-1:launch多节点启动与脚本配置

目录 0 专栏介绍1 ROS2的启动脚本优化2 ROS2多节点启动案例2.1 C架构2.2 Python架构 3 其他格式的启动文件3.1 .yaml启动3.2 .xml启动 0 专栏介绍 本专栏旨在通过对ROS2的系统学习&#xff0c;掌握ROS2底层基本分布式原理&#xff0c;并具有机器人建模和应用ROS2进行实际项目的…

Redis 中的 Zset 数据结构详解

目录 用法 1. 增 2. 删 3. 查 4. 交&#xff0c;并 编码方式 应用场景 Redis 中的 Zset&#xff08;有序集合&#xff09;是一种将元素按照分数进行排序的数据结构。与上篇写的SetRedis 中的 Set 数据结构详解不同&#xff0c;Zset 中的每个元素都关联一个浮点数类型的…

QT C++ 基于word模板 在书签位置写入文字和图片

如果你有按模版批量自动化操作word文件的需求&#xff0c;那么本文能给你一定的帮助。 它能满足你程序自动化生成报表的需求。常常用于上位机、测试仪器的软件中。 需要你你自己做个word模版文档&#xff0c;添加2个书签。点按钮&#xff0c;会按照你的模板文档生成一个同样的…

如何使用 Midjourney 进行 UI/UX 设计

图片由Midjourney创建 UI/UX 设计中的 AI 艺术彻底改变了游戏规则&#xff0c;开辟了惊人的可能性。Midjourney 可以在几秒钟内启动大量设计选项&#xff0c;让您的工作变得更轻松、更快捷。 在本文中&#xff0c;我将向您展示一些为 UI/UX 设计创建 AI 艺术的技巧。 要事第…

TH方程学习(3)

一、编程实现 根据论文给出的案例&#xff0c;使用TH方程进行数值仿真 1.初始化条件 %% 参考文献<New State Transition Matrix for Relative Motion on an Aribitrary Elliptical Orbit> %% 作者 Yamanaka Koji clc;clear global miu Re miu 3.986e5; Re 6378.137;…

数据挖掘与机器学习——关联规则与协同过滤

目录 推荐算法的目的 如何进行推荐&#xff1a; 关联规则 关联规则挖掘&#xff1a; 应用&#xff1a; 案例&#xff1a;啤酒与尿布 定义&#xff1a; 关联规则的度量&#xff1a; 支持度 置信区间 度量 关联规则挖掘 定义 步骤 apriori算法 定律&#xff1a; …

「手把手prompt1」相关介绍

「手把手prompt1」相关介绍 在人工智能领域迅速发展的当下&#xff0c;“prompt” 这个术语正逐渐成为焦点。本文将带您深入了解prompt的本质&#xff0c;以及它如何影响我们与AI系统的互动。您将学习到&#xff0c;通过精确的指令设计&#xff0c;可以引导AI系统产出精确和有…

GEYA格亚GRT8-M多种功能时间继电器交流AC220V DC24V延时断开小巧

品牌 GEYA 型号 GRT8-M1 AC/DC12-240 产地 中国大陆 颜色分类 GRT8-M1 A220,GRT8-M1 AC/DC12-240,GRT8-M2 A220,GRT8-M2 AC/DC12-240 GRT8-M&#xff0c;多功能型&#xff0c;时间继电器&#xff1a;LED指示灯&#xff0c;触头容量大&#xff0c;电压超宽&#xff0c;阻…

Ollama本地运行 Codestral-22B-v0.1

Ollama本地运行 Codestral-22B-v0.1 0. 引言1. 运行 codestral:22b-v0.1-q8_02. 简单测试下它的代码能力 0. 引言 Mixtral 5月30日发布了 Codestral-22B-v0.1。 Codestrall-22B-v0.1 在 80 多种编程语言的多样化数据集上进行训练&#xff0c;包括最流行的语言&#xff0c;例如…

3. MySQL 数据表的基本操作

文章目录 【 1. MySQL 创建数据表 】【 2. MySQL 查看表 】2.1 DESCRIBE/DESC 以表格的形式展示表2.2 SHOW CREATE TABLE 以SQL语句的形式展示表 【 3. MySQL 修改数据表 】3.1 修改表名3.2 修改表字符集3.3 添加字段在末尾添加字段在开头添加字段在中间添加字段 3.3 修改/删除…

【多线程开发 3】从源码到实践CompletableFuture

【多线程开发 3】从源码到实践CompletableFuture 2024年5月22日 本文将从以下几个点讲解CompletableFuture&#xff1a; 前身 是什么&#xff1f; 可以用来做什么&#xff1f; 源码原理 实战 其他包装类 前身 CompletableFuture的依赖如图所示&#xff1a; 所以我打…

二叉树的顺序结构及实现(堆的实现)

一.二叉树的顺序结构&#xff1a; 普通的二叉树是不适合用数组来存储的&#xff0c;因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆 ( 一种二叉树 ) 使用顺序结构的数组来存储&#xff0c;需要注意的是这里的堆和操作系统 虚拟进程地址…

C++入门3——类与对象2(类的6个默认成员函数)

目录 1.类的6个默认成员函数 2. 构造函数 2.1 构造函数的概念 2.2 构造函数的特性 3. 析构函数 3.1 析构函数的概念 3.2 析构函数的特性 4.拷贝构造函数 4.1 拷贝构造函数的概念 4.2 拷贝构造函数的特性 5.赋值运算符重载函数 5.1运算符重载函数 5.2 赋值运算符重…

探索文档解析技术,推动大模型训练与应用

探索文档解析技术&#xff0c;推动大模型训练与应用 0. 前言1. CCIG 20241.1 会议简介1.2 大模型技术及其前沿应用论坛1.3 走进合合信息 2. 大模型时代2.1 大模型的发展与应用2.2 大模型面临的挑战 3. 文档解析技术3.1 文档解析技术难点3.2 TextIn 文档解析算法流程 4. 大模型时…

UE5 Http Server

前言 最近要用UE 作为一个服务器去接收来自外部的请求&#xff0c;从而在UE中处理一些内容&#xff0c;但是之前只做过请求&#xff0c;哪整过这玩意&#xff0c;短期内还得出结果&#xff0c;那怎么搞嘞&#xff0c;本着省事的原则就找找呗&#xff0c;有没有现成的&#xff0…