【Linux】第三十二站:命名管道

文章目录

  • 一、命名管道介绍
  • 二、编码
    • 1.mkfifo
    • 2.unlink
    • 3.一个简单的例子
    • 4.修改

一、命名管道介绍

管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。

如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。

命名管道是一种特殊类型的文件

image-20240120181817217

我们可以直接使用下面的命令去创建命名管道

mkfifo myfifo

image-20240120182450551

它的文件类型是以p开头的,也就是命名管道

其实这个myfifo命名管道文件,它在磁盘中并没有数据,它更多的只是一种符号

如下所示

当我们左侧将内容输入到管道的时候,左侧会先进入阻塞。直到右侧使用cat拿到数据以后,左侧才会结束

image-20240120182624167

首先这两个指令是两个进程,这两个进程是毫无关系,但是他们是可以利用这个命名管道进行通信的

也可以看到,在写入的过程中,命名管道的大小一直是0

image-20240120183043910

我们也知道,如果两个不同的进程,打开同一个文件的时候,在内核中,操作系统也是打开一个文件,还是我们前面的这一套

image-20240120210716329

所以:

进程间通信的前提:先让不同的进程看到同一份资源

现在我们的这个管道文件其实就是一个内存级文件,它是不需要刷盘的!

那么我们怎么保证我们两个进程打开的是同一个文件呢?

只要同路径下的同一个文件名即可–>路径 + 文件名具有唯一性

二、编码

1.mkfifo

如下所示

image-20240120212754825

上面的函数可以去创建一个管道文件,第一个参数是路径,第二个是管道的权限是什么,如果成功是0,否则返回-1

如下代码所示

image-20240121123911378

image-20240121123855603

2.unlink

如果我们想要删除一个文件我们可以使用unlink接口

image-20240121124057956

如果成功,返回,如果失败返回-1

如下代码所示

image-20240121124451755

我们可以先编译运行一下,我们会发现会先报错说管道文件已经存在,这是正常的,因为我们之前的并没有删除掉

image-20240121124438918

当我们将原来的管道删除以后,重新运行,就可以看到了

image-20240121125130086

3.一个简单的例子

#pragma once
#include <iostream>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <string>
#define FIFO_FILE "./myfifo"
#define MODE 0664

enum 
{
    FIFO_CREATE_ERR = 1,
    FIFO_DELETE_ERR,
    FIFO_OPEN_ERR
    
};
using namespace std;
#include "comm.hpp"

int main()
{
    int fd = open(FIFO_FILE,O_WRONLY);
    if(fd < 0)
    {
        perror("clinet open file fail...");
        exit(FIFO_OPEN_ERR);
    }
    cout << "client open success" <<endl;
    string line;
    while(1)
    {
        cout << "Please Enter@ ";
        getline(cin,line);
        write(fd, line.c_str(), line.size());
    }

    close(fd);
    cout << "客户端关闭啦!..." << endl;
    return 0;
}
#include "comm.hpp"
using namespace std;

int main()
{
    //创建一个管道
    int n = mkfifo(FIFO_FILE, MODE);
    if(n == -1) 
    {
        perror("mkfifo");
        exit(FIFO_CREATE_ERR);
    }
    //开始通信
    int fd = open(FIFO_FILE,O_RDONLY);
    if(fd < 0)
    {
        perror("open:");
        exit(FIFO_OPEN_ERR);
    }
    cout <<"server open file sueccess" <<endl;

    while(1)
    {
        char buffer[1024] = {0}; 
        ssize_t x = read(fd, buffer, sizeof(buffer) - 1);
        if(x > 0)
        {
            buffer[x] = 0;
            cout << "服务器收到客户端发送的消息:"<< buffer <<endl;

        }
        else if(x == 0)
        {
            cout << "客户端关闭,服务器关闭" << endl;
            break;
        }
        else 
        {
            break;
        }
    }
    close(fd);
    //关闭信道
    int m = unlink(FIFO_FILE);
    if(m == -1)
    {
        perror("unlink:");
        exit(FIFO_DELETE_ERR);
    }

    return 0;
}

如上代码所示,最终的运行结果为

当我们先打开服务端的时候,我们发现服务端创建了管道,但是并没有打印出server open file success,这说明open处阻塞了

image-20240121153225268

当我们一旦打开了客户端,服务端和客户端几乎同时打开成功。这说明,命名管道文件需要写端和读端都打开的时候才可以,否则只打开其中一个会进入阻塞。我们可以理解为这是为了防止只打开读端,不打开写端的管道会出现读入0的情况。只打开写端,不打开读端会杀掉写端的进程

image-20240121153337884

然后就可以通信了

最终我们我们关闭客户端的同时,由于关闭了写端,但是读端没有关闭,就会读入0,最终服务端的代码逻辑会检测到这个0,从而结束进程

image-20240121153654275

同样的,如果我们先关闭了服务端,那么就会杀掉客户端的进程

image-20240121153931796

4.修改

我们现在对上面的代码进行一下小小的修改,使代码变得更加优雅

如下所示,我们让创建管道和销毁管道变成一个类,这样的话,就不需要我们自己去手动控制了

#pragma once
#include <iostream>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <string>
#define FIFO_FILE "./myfifo"
#define MODE 0664

enum 
{
    FIFO_CREATE_ERR = 1,
    FIFO_DELETE_ERR,
    FIFO_OPEN_ERR
    
};

class Init
{
public:
    Init()
    {
        //创建一个管道
        int n = mkfifo(FIFO_FILE, MODE);
        if(n == -1) 
        {
            perror("mkfifo");
            exit(FIFO_CREATE_ERR);
        }
    }
    ~Init()
    {
        //关闭信道
        int m = unlink(FIFO_FILE);
        if(m == -1)
        {
            perror("unlink:");
            exit(FIFO_DELETE_ERR);
        }
    }

};

客户端还是不变的

using namespace std;
#include "comm.hpp"

int main()
{
    int fd = open(FIFO_FILE,O_WRONLY);
    if(fd < 0)
    {
        perror("clinet open file fail...");
        exit(FIFO_OPEN_ERR);
    }
    cout << "client open success" <<endl;
    string line;
    while(1)
    {
        cout << "Please Enter@ ";
        getline(cin,line);
        write(fd, line.c_str(), line.size());
    }

    close(fd);
    cout << "客户端关闭啦!..." << endl;
    return 0;
}

下面是服务端,就可以通过一个变量的定义来控制前面的创建管道和关闭管道了

#include "comm.hpp"
using namespace std;

int main()
{
    Init in;
    //开始通信
    int fd = open(FIFO_FILE,O_RDONLY);
    if(fd < 0)
    {
        perror("open:");
        exit(FIFO_OPEN_ERR);
    }
    cout <<"server open file sueccess" <<endl;

    while(1)
    {
        char buffer[1024] = {0}; 
        ssize_t x = read(fd, buffer, sizeof(buffer) - 1);
        if(x > 0)
        {
            buffer[x] = 0;
            cout << "服务器收到客户端发送的消息:"<< buffer <<endl;

        }
        else if(x == 0)
        {
            cout << "客户端关闭,服务器关闭" << endl;
            break;
        }
        else 
        {
            break;
        }
    }
    close(fd);
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

<软考高项备考>《论文专题 - 78 风险管理(10)》

10 论文-历年真题解析 10.1 2005年上半年真题 请围绕“项目的风险管理”论题&#xff0c;分别从以下三个方面进行论述&#xff1a; 1&#xff0e;概要叙述你参与管理过的信息系统项目&#xff08;项目的背景、发起单位、目的、项目周期、交付的产品等&#xff09;&#xff0c…

【排序算法】五、冒泡排序(C/C++)

「前言」文章内容是排序算法之冒泡排序的讲解。&#xff08;所有文章已经分类好&#xff0c;放心食用&#xff09; 「归属专栏」排序算法 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 冒泡排序1.1 原理1.2 代码实现&#xff08;C/C&#xff09;1.3 特性总结 冒泡排序 1.1…

每日一题——1295.统计位数为偶数的数字

方法一 个人方法&#xff1a; 想知道整数型数字有多少位&#xff0c;可以直接把数字转字符&#xff0c;看字符的长度就是数字的位数 var findNumbers function(nums) {let count0for(let num of nums){let strnumif(str.length%20) count}return count }; 消耗时间和内存情况…

uni-app使用HBuilderX打包Web项目

非常简单&#xff0c;就是容易忘记 一、找到manifest.json配置Web配置 二、源码视图配置 "h5" : {"template" : "","domain" : "xxx.xx.xx.xxx","publicPath" : "./","devServer" : {&quo…

【Java程序员面试专栏 专业技能篇】MySQL核心面试指引(一):基础知识考察

关于MySQL部分的核心知识进行一网打尽,包括三部分:基础知识考察、核心机制策略、性能优化策略,通过一篇文章串联面试重点,并且帮助加强日常基础知识的理解,全局思维导图如下所示 本篇Blog为第一部分:基础知识考察,子节点表示追问或同级提问 基本概念 包括一些核心问…

什么是葡萄酒“质量三级标准”?

在葡萄酒的世界里有一个笼统的级别分为&#xff1a;入门、精品和顶级。那么&#xff0c;对应这三个级别的标准都是什么呢&#xff1f; 入门级别的标准&#xff1a;入门级别的酒首先喝起来新鲜且顺口。新鲜很容易理解&#xff0c;就是没有腐熟水果的味道&#xff0c;也就是“罐…

8.3最大自序和(LC53-M)

算法&#xff1a; 如果 -2 1 在一起&#xff0c;计算起点的时候&#xff0c;一定是从 1 开始计算&#xff0c;因为负数只会拉低总和&#xff0c;这就是贪心贪的地方&#xff01; &#xff08;-21&#xff0c;起点为负数&#xff0c;加上后面的数&#xff0c;只会让和变小&…

《WebKit 技术内幕》之六(3): CSS解释器和样式布局

3 WebKit布局 3.1 基础 当WebKit创建RenderObject对象之后&#xff0c;每个对象是不知道自己的位置、大小等信息的&#xff0c;WebKit根据框模型来计算它们的位置、大小等信息的过程称为布局计算&#xff08;或者称为排版&#xff09;。 图描述了这一过程中涉及的主要WebKit…

浅谈 ret2text

文章目录 ret2text无需传参重构传参函数调用约定x86x64 ret2text ret2text就是执行程序中已有的代码&#xff0c;例如程序中写有system等系统的调用函数 无需传参 如果程序的后门函数参数已经满足 getshell 的需求&#xff0c;那么就可以直接溢出覆盖 ret 地址不用考虑传参问…

SystemC学习笔记(三) - 查看模块的波形

简述 波形在Simulation/Emulation中地位十分重要&#xff0c;尤其是在研发初期&#xff0c;只能通过波形来查看软件hang住的位置。 对于TLM来说&#xff0c;查看波形一般是指查看pvbus上的transaction&#xff0c;而对于SystemC本身来说&#xff0c;查看波形就是使用Gtkwave或…

WeChall

WeChall-Scored Challenges 一、Get Sourced二、Stegano I三、Crypto - Caesar I四、WWW-Robots五、 ASCII六、URL七、Christmas Hippety八、No DNS 网站链接&#xff1a;https://www.wechall.net/challs/Training/by/chall_score/ASC/page-1 一、Get Sourced 题目链接&#…

HTML+JavaScript-01

说明 之前有一篇JavaWeb-JavaScript中只是简单介绍了一点JavaScript的内容&#xff0c;这篇笔记算是续写的&#xff0c;但是从01开始编号。 引入js文件 html、css、js俗称前端三剑客&#xff0c;一般都是分开写&#xff0c;先写框架、再写css、最后写js。因此在工程量大的情…

HarmonyOS—配置开发环境

应用/服务支持API Version 4至9&#xff0c;首次使用DevEco Studio&#xff0c;工具的配置向导会引导您下载SDK及工具链。配置向导默认下载 API Version 9的SDK及工具链&#xff0c;如需下载API Version 4至8&#xff0c;可在工程配置完成后&#xff0c;进入HarmonyOS SDK界面手…

福建专业建筑清水模板 — 安全可靠的选择

在福建地区的建筑工程中&#xff0c;选择高质量的清水模板对于确保结构的美观和工程的安全至关重要。我们能强优品木业提供的专业建筑清水模板&#xff0c;以其卓越的质量和安全性&#xff0c;成为施工团队的首选。 产品特性 优质材料制作&#xff1a;选用高品质木材制作&…

机械设计-哈工大课程学习-螺纹连接

圆柱螺纹主要几何参数螺纹参数 ①外径&#xff08;大径&#xff09;&#xff0c;与外螺纹牙顶或内螺纹牙底相重合的假想圆柱体直径。螺纹的公称直径即大径。 ②内径&#xff08;小径&#xff09;&#xff0c;与外螺纹牙底或内螺纹牙顶相重合的假想圆柱体直径。 ③中径&#xff…

React 初次接触

背景 还是为了完善高大上的在线文档系统&#xff0c;虽然比着葫芦画瓢的修改了一些所谓的代码&#xff0c;慢慢的才发现&#xff0c;原来这就是传说中的React&#xff0c;所以有比较又要囫囵吞枣一下React。 基本原理 参照《React技术揭秘》 网上有电子版 &#xff0c;应该是…

selenium-java中切换iframe

1、当iframe中有固定的name或者id时可以通过name和id进行切换,代码如下 driver.switchTo().frame("name"); 2、当iframe中没有固定的name或者id时可以通过iframe角标进行切换&#xff0c;在浏览器通过ctrlf快捷键&#xff0c;搜索标签框输入//iframe;来查看当前ifr…

11、Kafka ------ Kafka 核心API 及 生产者API 讲解

目录 Kafka核心API 及 生产者API讲解★ Kafka的核心APIKafka包含如下5类核心API&#xff1a; ★ 生产者APIKafka 的API 文档 ★ 使用生产者API发送消息 Kafka核心API 及 生产者API讲解 官方文档 ★ Kafka的核心API Kafka包含如下5类核心API&#xff1a; Producer API&#x…

一维数组2和二维数组1

1.一维数组在内存中的储存 在前面创建的数组中&#xff0c;每个元素是怎么储存的呢&#xff1f;我们通过观察元素的地址来看看吧。 %p是用来打印地址的。 结果为&#xff1a; 由此可看出每个地址都相隔一个int类型的距离&#xff0c;可以看出数组在内存中是连续存放的。也就是…

Pytest 测试框架与Allure 测试报告——Allure2测试报告-L1

目录&#xff1a; allure2安装 Allure2介绍Allure2报告展示Allure2报告展示-首页概览Allure2报告展示-用例详情页Allure2安装Allure2下载与安装Allure环境验证插件安装-Python插件安装-Java验证插件安装-Javaallure2运行方式 生成测试报告流程使用Allure2运行方式-Python使用A…