进程间通信 —— 《命名管道》

news2024/11/24 18:50:12

文章目录

  • 前言:
  • 命名管道的原理:
  • 代码编写:

前言:

在前面的一文,我们主要介绍了关于进程间的通信是如何实现的,以及引入了进程间通信的前提——“要让两个进程在OS中看到同一份资源”,而对于父子进程来说,子进程是通过继承父进程的struct files_struct来看到同一个文件的缓冲区,因此那个对应的缓冲区就是匿名管道,它们都看到了缓冲区这么一个同一份资源。那现在如何使得两个独立的进程实现通信?

命名管道的原理:

我们先来回顾一下创建进程再从磁盘打开文件的过程,一下在之前讲解文件标识符的时候都有涉及到,如果忘记了可以看看我之前写过的博客。

image-20241012164946363

现在我们创建进程B来讲讲俩进程要是想实现通信该怎么做:
image-20241012165415861

在创建进程B的时候,由于进程具有独立性,进程B并不会像子进程那样继承进程A的struct files_struct,而是会自己创建一个属于自己的struct files_struct

那还有必要再创建一个struct file和对应的缓冲区吗?
——有必要创建struct file但没必要创建新的缓冲区,因为两个进程实现了不一样的操作,我们想让进程B写入数据,而进程A要读数据。而对于缓冲区,着我们就没必要创建了,因为针对的是同一个文件,操作系统不做浪费时间和浪费空间的事情。

image-20241012171108697

我们在处理匿名管道的时候我们并不会去关心匿名管道是不是会刷新到缓冲区,匿名管道是一种内存级别的通信机制,它允许在同一台计算机上的不同进程间进行高效的数据传输。这种通信方式强调数据的快速传递和共享,因此它直接在内存中创建缓冲区来存储和传输数据。磁盘的访问速度相对较慢,如果匿名管道的数据需要频繁地刷新到磁盘,那么将严重影响数据传输的效率。而内存级别的通信则能够显著提高数据传输的速度,因为它避免了磁盘访问的延迟。

而命名管道却有这个困扰,这是因为命名管道中是会有一个具体的路径名,而匿名管道并没有文件系统的路径文件名,因此不会与磁盘文件有关联。但是其实命名管道其实也不会刷新至缓冲区,而是会出现在磁盘中然后是会以g开头的文件标记,这就能保证不会刷新到缓冲区。

输入指令:mkfifo myfifo
image-20241012174500579

那么就能标记这个是个命名管道,以g开头的文件,所以不会刷新到缓冲区。

综上所述,我们这个磁盘文件所对应的内核级的缓冲区就是——命名管道
image-20241013003129759

下面我们来运用一下命名管道:

代码编写:

现在我们想要实现两个独立的进程,一个是服务端(server)进程A,一个是客户端(client)B,服务端A负责接收数据,客户端B负责写数据。而对于命名管道的创建我们需要让服务端来进行管理,现在我们来介绍介绍关于命名管道的一些接口:

  • int mkfifo(const char *pathname, mode_t mode);其中参数pathname表示的是你给命名管道起的名字,而参数mode表示你该命名管道的权限。
  • int unlink(const char *pathname);该接口时实现管道的释放的。

所以我们就可以通过封装和实现接口,编写下面一个简单的小项目,命名管道的使用。

还有就是我们一定要保证当服务端(server)读到0的时候,就代表这客户端(client)退出了,服务端(server)同时也要进行退出。当先退出server,根据管道的五大特性中,若是读端关闭,则写端也会自动关闭!

一定是要先打开 服务端(server)再打开客户端(client),不然client就会找不到管道文件,就直接返回了!

namedpipe.hpp:

#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cerrno>
#include <fcntl.h>

const std::string pipe_path = "./myfifo";
#define DEFAULT_FD -1
#define Server 1
#define Client 2
#define READ O_RDONLY
#define WRITE O_WRONLY

class NamedPipe
{
private:
    void OpenNamedPipe(int mode)
    {
        _fd = open(pipe_path.c_str(), mode);
        if (_fd < 0)
        {
            perror("open");
            exit(1);
        }
        std::cout << "NamedPipe 打开成功!" << std::endl;
    }

public:
    NamedPipe(std::string path, int user)
        : _path(path), _user(user), _fd(DEFAULT_FD)
    {
        if (_user == Server)
        {

            int n = mkfifo(pipe_path.c_str(), 0666);
            if (n < 0)
            {
                perror("mkfifo");
                exit(1);
            }
            std::cout << "命名管道creat完毕!" << std::endl;
        }
    }

    void OpenNamedPipeByRead()
    {
        OpenNamedPipe(READ);
    }

    void OpenNamedPipeByWrite()
    {
        OpenNamedPipe(WRITE);
    }

    int WriteInPipe()
    {
        std::string message;
        std::cout << "Pleast Input> ";
        std::getline(std::cin, message);
        int n = write(_fd, message.c_str(), message.size());
        if (n < 0)
        {
            perror("write");
            exit(1);
        }
        return n;
    }

    int ReadFromPipe(std::string *out)
    {
        char file_buffer[1024];
        int n = read(_fd, file_buffer, sizeof(file_buffer));
        if (n > 0)
        {
            file_buffer[n] = 0;
            *out = file_buffer;
        }
        return n;
    }

    ~NamedPipe()
    {
        if (_user == Server)
        {
            int n = unlink(pipe_path.c_str());
            if (n < 0)
            {
                perror("mkfifo");
                exit(1);
            }
            std::cout << "命名管道free完毕" << std::endl;
        }
    }

private:
    std::string _path;
    int _user;
    int _fd;
};

client.cpp:

#include "namedpipe.hpp"

int main()
{
    NamedPipe mypipe(pipe_path, Client);
    mypipe.OpenNamedPipeByWrite();
    std::cout << "Hi I am Client" << std::endl;
    while (true)
    {
        mypipe.WriteInPipe();
    }

    return 0;
}

server.cpp:

#include "namedpipe.hpp"

// 当前为服务端,负责创建命名管道和释放管道

int main()
{
    NamedPipe mypipe(pipe_path, Server);
    mypipe.OpenNamedPipeByRead();
    std::cout << "Hi I am Server" << std::endl;

    while (true)
    {
        std::string out;
        int n = mypipe.ReadFromPipe(&out);
        if (n > 0)
        {
            std::cout << "Client say> " << out << std::endl;
        }
        else if (n == 0)
        {
            std::cout << "client退出, my turn!" << std::endl;
            break;
        }
        else
        {
            perror("read");
            exit(1);
        }
    }

    return 0;
}

在这里插入图片描述

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

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

相关文章

Spring Boot知识管理:智能搜索与分析

3系统分析 3.1可行性分析 通过对本知识管理系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本知识管理系统采用JAVA作为开发语言&#xff0c;Spring Boot框…

HTML+CSS实现固定的半透明底部导航栏

实现固定的半透明底部导航栏 在网页设计中&#xff0c;固定底部导航栏是一种常见的设计模式&#xff0c;尤其适用于移动端或简洁的网页布局。通过CSS&#xff0c;我们可以轻松实现固定位置、半透明效果、以及图片的动态缩放。本文将详细介绍如何使用HTML和CSS实现一个固定且具…

stderr和磁盘理解

1.stderr stderr文件默认的文件标识符是2&#xff0c;指向显示器&#xff0c;用来输出错误信息 #include<stdio.h>int main() {fprintf(stdout,"hello stdout\n");fprintf(stderr,"hello stderr\n");return 0; }stdout和stderr默认是指向显示器的&…

Postman发送GET、POST请求

Postman发送GET、POST请求 GET请求 在这里选择GET请求&#xff0c;接着输入请求的URL&#xff0c;点击发送即可看到服务端返回的数据。 POST请求 post请求通常会携带body数据&#xff0c;比get请求麻烦一点的是需要在Body里输入要携带的body数据&#xff0c;按照箭头所指示的…

千万级的大表,是如何产生的?

千万级的大表&#xff0c;是如何产生的? 我们小公司没有大表。。。 大家好&#xff0c;我是皇子。 前面的文章在介绍了《设计支持千万级的大表&#xff0c;有哪些数据库规范&#xff1f;》&#xff0c;实际上不管是否到达千万级&#xff0c;这些规范都是适用的。 那有人会…

git合并冲突未解决完导致Rebasing,无法切分支解决方案

分支前面出现Rebasing 进入项目目录中.git目录&#xff0c;手动删除index.lock文件&#xff08;相当于分支的锁&#xff0c;有这个就是不让你动&#xff0c;得删了&#xff09; 然后在git控制台输入git rebase --abort命令回滚到本地合并处理之前&#xff0c;然后再进行其他处…

树莓派应用--AI项目实战篇来啦-11.OpenCV定位物体的实时位置

1. 介绍 本项目通过PCA9685舵机控制模块控制二自由度舵机云台固定在零点位置&#xff0c;然后通OpenCV检测到黄色小熊&#xff0c;找到中心位置并打印出中心位置的坐标&#xff0c;通过双色LED灯进行指示是否检测到目标&#xff0c;本项目为后面二维云台追踪物体和追踪人脸提供…

【Windows】【DevOps】Windows Server 2022 安装ansible,基于powershell实现远程自动化运维部署 入门到放弃!

目标服务器安装openssh server参考 【Windows】【DevOps】Windows Server 2022 在线/离线 安装openssh实现ssh远程登陆powershell、scp文件拷贝-CSDN博客 注意&#xff1a;Ansible不支持Windows操作系统部署 根据官方说明&#xff1a; Windows Frequently Asked Questions —…

C语言初阶-数据类型和变量【下】

紧接上期------------------------->>>C语言初阶-数据类型和变量【上】 全局变量和局部变量在内存中存储在哪⾥呢&#xff1f; ⼀般我们在学习C/C语⾔的时候&#xff0c;我们会关注内存中的三个区域&#xff1a; 栈区 、 堆区 、 静态区 。 内存的分配情况 局部变量是…

STM32 RTC实时时钟 F407 寄存器

RTC介绍 STM32F1: RTC模块拥有一组连续计数的计数器&#xff0c;在相应软件配置下&#xff0c;可提供时钟日历的功能。 即在F1系列&#xff0c;RTC的日历部分只有一个32位的寄存器 该寄存器直接存放 时间戳 的值&#xff0c;即&#xff1…

LeetCode 279. 完全平方数(经典必会)

LeetCode 279. 完全平方数 给你一个整数 n &#xff0c;返回 和为 n 的完全平方数的最少数量 。 完全平方数 是一个整数&#xff0c;其值等于另一个整数的平方&#xff1b;换句话说&#xff0c;其值等于一个整数自乘的积。例如&#xff0c;1、4、9 和 16 都是完全平方数&#x…

java中连接Mysql以及PreparedStatement如何防止sql注入

目录 JDBC 使用JDBC连接到MySQL 使用 Statement 使用 PreparedStatement Statement 和 PreparedStatement 区别 在 java 中如何连接到 MySQL 数据库&#xff0c;执行 SQL 查询&#xff0c;并处理查询结果&#xff1f; JDBC java 程序连接到 mysql&#xff0c;首先需要下…

Dev-C++萌新福利2

朝鲜球作品原创 1 符号认识&#xff1a; 1.1简单例题1 1.2简单例题22奇奇怪怪的符号 2.1简单例题3 2.2符号表 2.2.1符号表中特殊符号 2.3符号使用代码样例&#xff08;部分&#xff09; 萌新福利 作品成本6999元&#xff0…

OSError: [Errno 22] Invalid argument:无效的参数完美解决方法

&#x1f6a8; OSError: [Errno 22] Invalid argument&#xff1a;无效的参数完美解决方法 &#x1f4a1; &#x1f6a8; OSError: [Errno 22] Invalid argument&#xff1a;无效的参数完美解决方法 &#x1f4a1;摘要引言正文1. 什么是 OSError: [Errno 22] Invalid argument&…

牛客.数字游戏​编辑牛客.体操队形(暴力搜索)​​​​​​​牛客.二叉树最大路径和​编辑牛客.排序子序列

目录 牛客.数字游戏​编辑 牛客.体操队形(暴力搜索) 牛客.二叉树最大路径和​编辑 牛客.排序子序列 牛客.数字游戏 难度不大&#xff0c;但是要注意&#xff0c;他这个快速输入与输出 import java.util.*; import java.io.*; import java.util.StringTokenizer; // 注意类名…

架构设计笔记-15-面向服务架构设计理论与实践

目录 知识要点 案例分析 1.微服务架构 2.微服务 3.微服务架构 4.SOA与微服务 5.基于微服务架构的系统/传统单体式系统 论文 1.论微服务架构及其应用 知识要点 服务组件体系结构&#xff08;Service Component Architecture&#xff0c;SCA&#xff09;是面向服务体系…

IT基础监控运维:监控易的深度解析与应用

在数字化转型加速的今天&#xff0c;IT系统的稳定性和高效运维成为了企业业务连续性的关键保障。IT基础监控作为运维工作的基石&#xff0c;其重要性不言而喻。本文将以监控易产品为核心&#xff0c;深入探讨IT基础监控的功能、特点及范围&#xff0c;为运维团队提供实用的参考…

销售管理之线索管理

一、线索获取&#xff1a;销售增长与市场洞察的双引擎 销售增长的基石 线索&#xff1a;销售旅程的起点&#xff1a;在销售的宏伟蓝图中&#xff0c;高质量的线索无疑是构筑成功的基石。缺乏持续、优质的线索供应&#xff0c;任何销售团队都难以跨越销售目标的重重山峦。以软…

Apktool:解包重打包工具

ApKtool是一个apk编译工具&#xff0c;能够反编译apk文件。 解包 使用命令apktool d test.apk 会在同目录下生成一个同名的文件夹 重打包 使用命令apktool b test 会在test文件夹里生成一个dist目录&#xff0c;在dist目录里有打包好的test.apk

Top6 最好的 Android 数据恢复软件免费获取

虽然在智能手机上随身携带您最喜爱的音乐收藏或珍贵的录音很方便&#xff0c;但如果您的设备出现技术问题或您不小心删除了文件&#xff0c;文件也有可能丢失。 不管文件是如何删除或丢失的&#xff0c;丢失那些珍贵的音频文件的痛苦对每个人来说都是一样的。这就是我们创建本…