【IPC】管道通信【命名管道】

news2024/10/6 6:47:52

文章目录

  • 1.管道小总结
  • 2.命名管道
    • 2.1认识命名管道
    • 2.2命名管道的应用小场景
    • 2.3模拟命名管道
      • 1.Lod.hpp
      • 2.common.hpp
      • 3.server.cxx
      • 4.client.cxx
  • 3.管道代码总结

1.管道小总结

linux-manualshouce

在Linux中,manual手册的编号用于区分手册的不同部分。这些编号通常用于man命令中,以便用户可以指定要查看的手册部分。man命令的编号对应关系如下:

用户命令(User Commands):通常包括可执行程序或shell命令。
系统调用(System Calls):由内核提供的函数。
库调用(Library Calls):程序库中的函数。
特殊文件(Special Files):通常位于/dev目录下的设备文件。
文件格式和约定(File Formats and Conventions):例如/etc/passwd等配置文件的格式。
游戏(Games)。
杂项(Miscellaneous):包括宏包和约定等其他内容。
系统管理命令(System Administration Commands and Daemons)。
此外,还有第9个部分,通常用于其他内容,比如内核例行程序(Kernel Routines)。

管道读写规则

  1. 当没有数据可读时
    O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据为止。
    O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。
  2. 当管道满的时候
    O_NONBLOCK disable: write调用阻塞,直到有进程读走数据
    O_NONBLOCK enable:调用返回-1,errno值为EAGAIN
  3. 如果所有管道写端对应的文件描述符被关闭,则read返回0
  4. 如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE,进而可能导致write进程退出
  5. 当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。
  6. 当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

原子性

要么做要么不做。无中间状态。
多执行流下数据出现并发访问时考虑。

2.命名管道

2.1认识命名管道

在这里插入图片描述

  1. 进程A打卡了文件file,进程B再去打开file时,OS识别到file已打开,则不再创建对应的file结构体,而是直接指向已有的file结构体。【OS中一般都会存在n多个进程,且存在像许多进程打开同一个文件的情况,如果对于已经打开的文件,另外的进程再去打开他时区创建一个新的file结构体,这无疑是巨大的时空浪费】
  2. 命名管道无疑是这样的一个存在,首先他是一个文件,其次他不用将数据刷新到磁盘。
  3. 该文件一定在系统路径中(路径具有唯一性)。该文件有名字,可以被打开,但是不会将内存数据刷新到磁盘。
  4. 至此,两个毫不相干的进程通过命名管道文件的路径看到同一份资源。【匿名管道通常应用于有血缘关系的进程,这也是匿名管道的一个缺点】

2.2命名管道的应用小场景

创建命名管道

在这里插入图片描述
在这里插入图片描述

场景1

在这里插入图片描述

场景2:输出重定向

在这里插入图片描述

在这里插入图片描述

条件编译
#ifndef _COMMON_H_
#define _COMMON_H_
#endif

这三句代码是C或C++编程语言中常用的预处理器指令,它们通常用于头文件中以防止头文件内容的多次包含(多重定义问题)。我来详细解释每句代码的含义:

#ifndef COMMON_H
这是一个条件编译指令,它检查是否定义了名为_COMMON_H_的宏(macro)。如果_COMMON_H_没有被定义,那么紧随其后的代码(直到遇到#endif或另一个条件编译指令)会被编译器包含(或编译)。
2. #define COMMON_H

这行代码定义了一个名为_COMMON_H_的宏。一旦这个宏被定义,再次遇到#ifndef _COMMON_H_时,由于_COMMON_H_已经被定义,所以其后的代码不会被再次包含。
3. #endif

这是一个结束标记,表示#ifndef条件编译指令的结束。

将这三行代码放在头文件common.h的开始处,可以确保无论这个头文件被包含多少次,其内部的内容都只会被编译器编译一次。这在处理循环包含或者复杂项目结构时非常有用,因为你可以避免函数或变量被多次定义,从而避免编译错误。
这样,当common.h首次被包含时,其内容会被编译;如果再次被包含,由于_COMMON_H_已经被定义,其内容不会被再次编译。

unlink()删除文件

在这里插入图片描述

rm和unlink的异同

在Linux中,rm和unlink都用于删除文件或目录,但它们在使用方式和功能上有一些重要的区别。

  1. 命令形式和使用方式:

rm 是一个更高级的、用户友好的命令,用于删除文件或目录。它可以处理多种复杂的情况,例如删除目录(使用 -r 或 -R 选项)或强制删除文件(使用 -f 选项)。
unlink 是一个较低级的系统调用,通常用于在编程中删除文件。在shell中,你可以使用 unlink 命令来删除文件,但它没有 rm 那么多的选项和功能。
2. 功能和行为:

在功能上,rm 和 unlink 基本上是一样的:它们都删除了指定的文件或目录。然而,由于 rm 提供了更多的选项,它可以更灵活地处理各种情况。
在行为上,rm 和 unlink 都减少了文件的链接计数。如果一个文件只有一个链接(即它是唯一被引用的),那么当这个链接被 rm 或 unlink 删除后,该文件占用的磁盘空间也会被释放。但是,如果一个文件有多个链接,那么删除其中一个链接只会减少链接计数,而不会释放磁盘空间。
3. 错误处理:

rm 在删除不存在的文件或目录时,会输出一个错误消息。然而,如果你使用 -f 选项,rm 会静默地忽略这些错误。
unlink 在遇到错误时,通常会返回一个错误代码,但具体的行为可能取决于你的shell和如何调用 unlink。
总的来说,rm 和 unlink 在功能上相似,但在使用方式和行为上有所不同。对于日常的文件删除任务,rm 通常是一个更好的选择,因为它提供了更多的选项和更友好的错误处理。而在编程中,你可能需要更直接地控制文件删除的过程,这时 unlink 可能更合适。

2.3模拟命名管道

1.Lod.hpp

#ifndef _LOG_H_
#define _LOG_H_

#include <iostream>
#include <ctime>

#define Debug 0
#define Notice 1
#define Warning 2
#define Error 3

const std::string tip[] ={
        "Debug",
        "Notice",
        "Warning",
        "Error"};

std::ostream &Log(std::string message, int option)
{
    // 获取时间戳 time_t timestamp; time(timestamp);
    time_t timestamp = time(nullptr);
    if (timestamp == std::time_t(-1))
    {
        std::cerr << "获取时间失败" << std::endl;
        exit(1);
    }

    // 获取格式化时间 tm *localtime(const time_t *__timer)
    tm *timeinfo = std::localtime(&timestamp);

    std::cout << " | "
              << 1900 + timeinfo->tm_year << "-"
              << 1 + timeinfo->tm_mon << "-"
              << timeinfo->tm_mday << " "
              << timeinfo->tm_hour << ":"
              << timeinfo->tm_min << ":"
              << timeinfo->tm_sec
              << " | "
              << tip[option]
              << " | "
              << message;

    return std::cout;
}

#endif

2.common.hpp

#ifndef _COMMON_H_
#define _COMMON_H_

#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <iomanip> 
#include "Log.hpp"

using namespace std;

#define MODE 0666
#define SIZE 128

string ipcPath = "./fifo.ipc";

#endif

3.server.cxx

#include "common.hpp"
#include <sys/wait.h>

static void IpcWithClient(int fd)
{
    char buffer[SIZE];
    while (true)
    {
        memset(buffer, '\0', sizeof(buffer));
        // 【OS写的时候不写\0 这里读的时候自然没有\0 我们空一个以免有需要在末尾加0】
        // 当然 上面的memset已经对所有单元都加了\0 这里只是通用的默认规范
        ssize_t s = read(fd, buffer, sizeof(buffer) - 1);

        if (s > 0) // read success
        {
            cout << "[" << getpid() << "] "
                 << "client say:> " << buffer << endl;
        }
        else if (s == 0) // end of file
        {
            cerr << "[" << getpid() << "] "
                 << "read end of file, clien quit, server quit too!" << endl;
            break;
        }
        else // read error
        {
            perror("IpcWithClient::read");
            break;
        }
    }
}

int main()
{
    // 1. 创建管道文件 int mkfifo(const char *__path, mode_t __mode)
    if (mkfifo(ipcPath.c_str(), MODE) < 0) //成功返回0 失败返回-1
    {
        perror("server::mkfifo");
        exit(1);
    }
    Log("创建管道文件成功", Debug) << " step 1" << endl;

    // 2. 打开管道文件
    int fd = open(ipcPath.c_str(), O_RDONLY);
    if (fd < 0)
    {
        perror("server::open");
        exit(2);
    }
    Log("打开管道文件成功", Debug) << " step 2" << endl;

    // 3. 开始进行IPC 服务端创建子进程去与客户端进行ipc
    int serverChildNum = 3;
    for (int i = 0; i < serverChildNum; i++)
    {
        pid_t id = fork();
        if (id == 0)
        {
            IpcWithClient(fd);
            exit(1);
        }
    }
    //阻塞式等待子进程 获取子进程退出状态 回收子进程
    for (int i = 0; i < serverChildNum; i++)
    {
        waitpid(-1, nullptr, 0);
    }

    // 4. 关闭文件
    close(fd);
    Log("关闭管道文件成功", Debug) << " step 3" << endl;

    unlink(ipcPath.c_str()); // int unlink(const char *__name)
    Log("删除管道文件成功", Debug) << " step 4" << endl;

    return 0;
}

4.client.cxx

#include "common.hpp"

int main()
{
    // 1. 获取管道文件 创建文件由server负责
    // 这里不加O_TRUNC 文件不存在client也不创建 失败是server的事情
    int fd = open(ipcPath.c_str(), O_WRONLY);
    if (fd < 0)
    {
        perror("client::open");
        exit(1);
    }

    // 2. 进行ipc
    string buffer;
    while (true)
    {
        cout << "Please input information:> ";
        //istream& getline<char, char_traits<char>, allocator<char>>(istream& __is, string& __str)
        std::getline(std::cin, buffer);
        write(fd, buffer.c_str(), buffer.size());
    }

    // 3. 关闭
    close(fd);
    return 0;
}

3.管道代码总结

  1. 模拟匿名管道: 父进程调用pipe() 创建匿名管道 记录pipefd 父子进程各自关闭不用的pipefd 之后父进程写到写端 子进程从读端读
  2. 模拟进程池: 父进程创建N个子进程 对每一个子进程之开启读端 父进程只开启写端 父进程随机选择一个子进程去执行它写到写端的命令 子进程阻塞等待获取从读端的命令 直到获取成功 否则一直阻塞等待
  3. 模拟命名管道:服务端进程创建命名管道 让子进程从fd里读信息后输出到显示器 客户端打开彼管道文件 向该fd写信息

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

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

相关文章

个人商城系统开源(发送手机验证码!)

原文地址&#xff1a;个人商城系统开源&#xff08;发送手机验证码&#xff01;&#xff09; - Pleasure的博客 下面是正文内容&#xff1a; 前言 由于近期实在没有什么话题可写和一些有趣的项目教程可以分享。所以我只能决定将我自己亲手编写的一个迷你迷你商城系统进行开源…

3 模型评估

3 模型评估 在测试AI系统中的模型训练和评估阶段,需要使用准备好的数据集对AI模型进行训练和评估。在训练过程中,应该对模型进行监控和调整,以确保模型的准确性和效果。在评估过程中,需要使用测试数据集对模型进行测试,以验证模型的准确性和效果。模型的评估也分为离线评…

通过一篇文章带你玩转git和GitHub

Git和Github的基本用法 前言一、Git和Github的基本用法背景下载安装安装 git for windows安装 tortoise gitgit安装过程中的一些选项 tortoise git汉化教程下载tortoise git汉化安装包安装tortoise git汉化安装包 三、使用 Github 创建项目注册账号创建项目下载项目到本地 四、…

视频批量混剪剪辑,批量剪辑批量剪视频,探店带货系统,精细化顺序混剪,故事影视解说,视频处理大全,精细化顺序混剪,多场景裂变,多视频混剪

前言 工具的产生源于dy出的火山引擎的云视频混剪制作是按分钟数收费的&#xff0c;这个软件既能实现正常混剪也能避免二次收费。属于FFMPEG合成的。 欢迎大家给一些好的建议和功能&#xff0c;回复可见&#xff0c;附加了一些天卡&#xff0c;周卡&#xff0c;请大家不要一人占…

【C++】函数模板和类模板

目录 1.泛型编程 2.函数模板 2.1函数模板的定义格式 2.2函数模板的实例化 2.3函数模板参数的匹配原则 3.类模板 3.1类模板的定义格式 3.2类模板的实例化 3.3模板的分离编译 1.泛型编程 泛型编程&#xff1a;编写与类型无关的通用代码&#xff0c;是代码复用的一种手段…

新一代 Git 工具,AI 赋能!深度集成、简化操作 | 开源日报 No.194

gitbutlerapp/gitbutler Stars: 7.2k License: NOASSERTION gitbutler 是一个基于 Git 的版本控制客户端。旨在为现代工作流程构建一个全新的 Git 分支管理工具。 虚拟分支&#xff1a;可以同时在多个分支上工作&#xff0c;而无需不断切换分支简化提交管理&#xff1a;通过拖…

如何转行成为产品经理?

转行NPDP也是很合适的一条发展路径&#xff0c;之后从事新产品开发相关工作~ 一、什么是NPDP&#xff1f; NPDP 是产品经理国际资格认证&#xff0c;美国产品开发与管理协会&#xff08;PDMA&#xff09;发起的&#xff0c;是目前国际公认的唯一的新产品开发专业认证&#xff…

stm32普通定时器脉冲计数(发送固定脉冲个数),控制步进电机驱动器

拨码开关设置驱动器&#xff0c;细分 方法思路&#xff1a;用通用定时器TIM2&#xff0c;1ms产生一次中断&#xff1b;在中断里做IO反转&#xff1b; 发送10个脉冲信号

Docker部署SimpleMindMap结合内网穿透实现公网访问本地思维导图

文章目录 1. Docker一键部署思维导图2. 本地访问测试3. Linux安装Cpolar4. 配置公网地址5. 远程访问思维导图6. 固定Cpolar公网地址7. 固定地址访问 SimpleMindMap 是一个可私有部署的web思维导图工具。它提供了丰富的功能和特性&#xff0c;包含插件化架构、多种结构类型&…

【漏洞复现】大华ICC智能物联综合管理平台token弱口令漏洞

Nx01 产品简介 大华智能物联综合管理平台 iConnection Center&#xff08;以下简称&#xff1a;ICC平台&#xff09;&#xff0c;是一套基于智能物联的综合业务管理平台软件&#xff0c;具备强大的后台服务能力&#xff0c;配套了B/S管理员端、C/S客户端、移动APP终端、小程序等…

Java的Writer类详解

咦咦咦&#xff0c;各位小可爱&#xff0c;我是你们的好伙伴——bug菌&#xff0c;今天又来给大家普及Java SE相关知识点了&#xff0c;别躲起来啊&#xff0c;听我讲干货还不快点赞&#xff0c;赞多了我就有动力讲得更嗨啦&#xff01;所以呀&#xff0c;养成先点赞后阅读的好…

Tomcat容器经常重启问题排查

报错代码: INFO [Catalina-utility-2] org.apache.catalina.core.StandardContext.reload Reloading Context with name [] has started1.查看内存占用情况:top 可以发现java线程正常情况下占用高达24%的内存资源 2.继续排查:top -Hp 29580 可以发现主要有子线程Catalina-ut…

汉服|高校汉服租赁网站|基于Springboot的高校汉服租赁网站设计与实现(源码+数据库+文档)

高校汉服租赁网站目录 目录 基于Springboot的高校汉服租赁网站设计与实现 一、前言 二、系统设计 三、系统功能设计 1、汉服信息管理 2、汉服租赁管理 3、公告管理 4、公告类型管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选…

Elasticsearch 通过索引阻塞实现数据保护深入解析

Elasticsearch 是一种强大的搜索和分析引擎&#xff0c;被广泛用于各种应用中&#xff0c;以其强大的全文搜索能力而著称。 不过&#xff0c;在日常管理 Elasticsearch 时&#xff0c;我们经常需要对索引进行保护&#xff0c;以防止数据被意外修改或删除&#xff0c;特别是在进…

关于STM32G070RBTx单片机使用HAL库往flash写数据的过程中死机问题

1.单片机型号:STM32G070RBTx 2.出现的问题 根据库函数FLASH_If_Write()的使用&#xff0c;我们分析往flash写数据的过程是把uint8_t 类型的数据(p_data)以地址的形式强转成uint64类型的&#xff0c;在一包128字节的数据时一次存储8位&#xff0c;存16次(packet_size/8)&#x…

简介:Deep Web和Dark Web

深网和暗网之间的区别是什么&#xff1f; “深网”和“暗网”是不能互换的术语。虽然整个暗网都是暗网的一部分&#xff0c;但反过来却不是这样。简单地说&#xff0c;深度网络是网络中没有被搜索引擎索引的任何部分。这包括在付费墙后面屏蔽其内容的网站、受密码保护的网站&a…

存货计价方式 比较-移动平均和批次计价

SAP常用的存货计价方式有 标准价格移动平均价格批次计价 标准价格常用于制造企业&#xff0c;今天的方案比较主要集中在销售型企业常用的移动平均价和批次计价 批次计价&#xff1a; 移动平均&#xff1a; 两种计价方式的Pros&Cons 比较 批次计价 移动平均优点 1…

韦根协议刷卡原理及代码实现

一、韦根协议原理 韦根接口在门禁行业广泛使用&#xff0c;是一个门禁行业的通信标准&#xff0c;通过两条数据线 DATA0&#xff08;D0&#xff09;和 DATA1 &#xff08;D1&#xff09;发送数据。目前用的最多的是韦根 34 和韦根 26&#xff0c;二者数据格式相同&#xff0c;…

【Python】科研代码学习:二 dataclass,pipeline

【Python】科研代码学习&#xff1a;二 dataclass&#xff0c;pipeline 前言dataclasspipeline 前言 后文需要学习一下 transformers 库&#xff0c;必要时会介绍其他相关的重要库和方法。主要是从源代码、别人的技术文档学习&#xff0c;会更快些。 dataclass Python中的数…