命名管道:简单案例实现

📟作者主页:慢热的陕西人

🌴专栏链接:Linux

📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言

本博客主要内容讲解了什么是命名管道,匿名管道和命名管道的区别,并且实现了一个案例来实践操作

文章目录

  • Linux命名管道
    • 1.概念
    • 2.创建一个命名管道
    • 3.匿名管道与命名管道的区别
    • 4.我们实现一个即时的输入输出
    • 5.完整代码

Linux命名管道

1.概念

  • 管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信
  • 如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道
  • 命名管道是一种特殊类型的文件

2.创建一个命名管道

  • 命名管道可以从命令行上创建,命令行方法是使用下面这个命令 :

    mkfifo filename

    image-20231128174723565

    见见猪跑:

    向管道写入:echo hello > fifo:我们发现程序卡住了,细节是我们查看fifo的文件的大小的时候,它却是0,因为我们知道管道是内存级文件,他的内容不会刷新到磁盘,所以我们看到的文件大小就是0,当我们cat < fifo也就是将fifo中的内容重定向输出到cat中打印出了hello

image-20231128193005159

那么上面的操作,是通过一个管道文件,让两个无关的进程实现的进程间的通信。那么我们知道进程间的通信就是要让两个进程看到同一个文件,那么这里我们是如何做到同一个文件呢?答案是路径,文件的唯一性就是由路径表示的!


那么我们到底是如何使用命名管道实现两个进程间的通信的:

①我们需要创建一个管道文件

这里我们需要用到一个系统接口mkfifo

image-20231128204130327

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

#include "comm.hpp"


using namespace std;
int main()
{
//1.创建管道文件,我们今天只需要创建一次
int n  = mkfifo(filename.c_str(),mode);
if(n != 0) //创建失败
{
  cout << errno << " : "<< strerror(errno)<<  endl;
  return 1;
}

return 0;
}

运行一下:

我们发现确实创建了文件:但是文件的权限却不是我们想要的0666,其实我们一下就能看出来原因是我们的umask不为零影响到了结果

image-20231128204311535

我们查看一个操作系统的接口:umask

image-20231128204715405

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

#include "comm.hpp"


using namespace std;
int main()
{
//1.创建管道文件,我们今天只需要创建一次
umask(0); //只影响当前进程的umask
int n  = mkfifo(filename.c_str(),mode);
if(n != 0) //创建失败
{
  cout << errno << " : "<< strerror(errno)<<  endl;
  return 1;
}

return 0;
}

运行一下看看:
image-20231128204930740

②让读写端进程分别按照自己的需求打开文件

 //1.不需要创建管道文件,我只需要打开对应的文件即可!
 int wfd = open(filename.c_str(), O_WRONLY);
 if(wfd < 0)
 {
     cerr << errno << " : "<< strerror(errno)<<  endl;
     return 1;
 }



 //1.创建管道文件,我们今天只需要创建一次
 umask(0); //只影响当前进程的umask
 int n  = mkfifo(filename.c_str(),mode);
 if(n != 0) //创建失败
 {
     cout << errno << " : "<< strerror(errno)<<  endl;
     return 1;
 }

③开始通信

//3.开始通信
 char buffer[NUM];
 while(true)
 {
     buffer[0] = 0; //初始化第一个位置为\0
     //读文件
     ssize_t n = read(rfd, buffer, sizeof(buffer) - 1);

     if(n > 0)
     {
         //读成功了
         buffer[n] = 0;
         printf("%s\n", buffer);
         fflush(stdout);
     }
     else if(n == 0)
     {
         //写端关闭
         cout << "client quit, me too" << endl;
         break;
     }
     else
     {
         //错误
         cout << errno << " : "<< strerror(errno)<<  endl;
         return 1;
     }
 }



 //2.开始通信
 char buffer[NUM];

 while(true)
 {
     cout << "请输入要写入的信息#";
     char* msg = fgets(buffer, sizeof(buffer), stdin);
     assert(msg);
     (void)msg;

     buffer[strlen(buffer) - 1] = 0;


     //当我们写入quit的时候退出写端
     if(strcasecmp(buffer, "quit") == 0) break;

     ssize_t n = write(wfd, buffer, strlen(buffer));
     assert(n >= 0); 
     (void)n;
 }

运行结果:

image-20231128223524668

3.匿名管道与命名管道的区别

  • 匿名管道由pipe函数创建并打开。
  • 命名管道由mkfifo函数创建,打开用open
  • FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义

4.我们实现一个即时的输入输出

就是我们输入管道的时候不用回车,而是选用输入一个字符就从管道输出:

我们要在client.cc端改变其向文件写入的方式,我们读取到字符c中,然后没输入一个字符就同步;

    while(true)
    {

        system("stty raw");  // 使终端驱动处于一次一字符模式
        char c = getchar();
        system("stty cooked");// 使终端驱动回到一次一行模式 

        ssize_t n = write(wfd, &c, sizeof(char));
        assert(n >= 0); 
        (void)n;
    }

运行结果:

打印结果

5.完整代码

client.cc

#include<iostream>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<cerrno>
#include<cassert>
#include"comm.hpp"


using namespace std;
int main()
{
    //1.不需要创建管道文件,我只需要打开对应的文件即可!
    int wfd = open(filename.c_str(), O_WRONLY);
    if(wfd < 0)
    {
        cerr << errno << " : "<< strerror(errno)<<  endl;
        return 1;
    }

    //2.开始通信
    char buffer[NUM];

    while(true)
    {

        // cout << "请输入要写入的信息#";
        // char* msg = fgets(buffer, sizeof(buffer), stdin);
        // assert(msg);
        // (void)msg;

        // buffer[strlen(buffer) - 1] = 0;

        system("stty raw");  // 使终端驱动处于一次一字符模式
        char c = getchar();
        system("stty cooked");// 使终端驱动回到一次一行模式 


        // //当我们写入quit的时候退出写端
        // if(strcasecmp(buffer, "quit") == 0) break;

        ssize_t n = write(wfd, &c, sizeof(char));
        assert(n >= 0); 
        (void)n;
    }

    return 0;
}

server.cc

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

#include "comm.hpp"


using namespace std;
int main()
{
    //1.创建管道文件,我们今天只需要创建一次
    umask(0); //只影响当前进程的umask
    int n = mkfifo(filename.c_str(),mode);
    if(n != 0) //创建失败
    {
        cout << errno << " : "<< strerror(errno)<<  endl;
        return 1;
    }

    cout << "创建文件成功!"<< endl;

    //2.打开文件
    int rfd = open(filename.c_str(), O_RDONLY);
    if(rfd < 0) //打开错误
    {
        cout << errno << " : "<< strerror(errno)<<  endl;
        return 2;
    }

    cout << "打开管道成功" << endl;

    //3.开始通信
    char buffer[NUM];
    while(true)
    {
        buffer[0] = 0; //初始化第一个位置为\0
        //读文件
        ssize_t n = read(rfd, buffer, sizeof(buffer) - 1);

        if(n > 0)
        {
            //读成功了
            printf("%c", buffer[0]);
            fflush(stdout);
        }
        else if(n == 0)
        {
            //写端关闭
            cout << "client quit, me too" << endl;
            break;
        }
        else
        {
            //错误
            cout << errno << " : "<< strerror(errno)<<  endl;
            return 1;
        }
    }


    //4.关闭文件
    close(rfd);

    unlink(filename.c_str());
    return 0;
}

comm.hpp

#pragma once

#include <iostream>
#include <string>


using namespace std;


#define NUM 65535 //管道缓冲区大小


string filename = "./fifo"; //文件名
mode_t mode = 0666; //打开方式

到这本篇博客的内容就到此结束了。
如果觉得本篇博客内容对你有所帮助的话,可以点赞,收藏,顺便关注一下!
如果文章内容有错误,欢迎在评论区指正

在这里插入图片描述

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

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

相关文章

咨询+低代码,强强联合为制造业客户赋能

内容来自演讲&#xff1a;沈毅 | 遨睿智库 | 董事长 & 王劭禹 | 橙木智能 | 联合创始人 摘要 文章主要讲述了智库董事长沈毅创办广告公司的经历&#xff0c;以及他在管理公司过程中遇到的问题和挑战&#xff0c;最后通过与明道云以及橙木智能联合创始人王邵禹老师的合作&…

java二十章多线程

概念 有很多工作是可以同时完成的&#xff0c;这种思想放在Java中被称为并发&#xff0c;并发完成每一件事被称为线程。 程序员可以在程序中执行多个线程&#xff0c;每一个线程完成一个功能//与其他线程并发执行&#xff0c;这种机制被称为多线程&#xff0c;并不算所有编程…

如何提高3D建模技能?

无论是制作影视动画还是视频游戏&#xff0c;提高3D建模技能对于你的工作都至关重要的。那么如何能创建出精美的3D模型呢&#xff1f;本文给大家一些3D建模技能方面的建议。 3D建模通过专门的软件完成&#xff0c;涉及制作三维对象。这项技能在视频游戏开发、建筑、动画和产品…

FFmpeg架构全面分析

一、简介 它的官网为&#xff1a;https://ffmpeg.org/&#xff0c;由Fabrice Bellard&#xff08;法国著名程序员Born in 1972&#xff09;于2000年发起创建的开源项目。该人是个牛人&#xff0c;在很多领域都有很大的贡献。 FFmpeg是多媒体领域的万能工具。只要涉及音视频领…

【Vulnhub 靶场】【DriftingBlues: 9 (final)】【简单】【20210509】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/driftingblues-9-final,695/ 靶场下载&#xff1a;https://download.vulnhub.com/driftingblues/driftingblues9.ova 靶场难度&#xff1a;简单 发布日期&#xff1a;2021年05月09日 文件大小&#xff1a;738 …

达索系统SOLIDWORKS 2024工程图新功能

工程图概述 设计模型不仅能比绘制直线更快&#xff1b;SOLIDWORKS 从模型中生成工程图&#xff0c;模型的参数和几何关系在工程图中被保留&#xff0c;这样工程图可反映模型的设计意图&#xff1b;模型或工程图中的更改反映在其相关文件中&#xff0c;这样更改起来更容易&…

map文件解析

Map文件内容分为以下五段&#xff1a; 1&#xff09;Section Cross References&#xff1a;模块、段(入口)交叉引用&#xff1b;(ASR编译生成的map文件没有输出该段信息) 2&#xff09;Removing Unused input sections from the image&#xff1a;移除未使用的模块&#xff1…

【Linux】基础IO--文件基础知识/文件操作/文件描述符

文章目录 一、文件相关基础知识二、文件操作1.C语言文件操作2.操作系统文件操作2.1 比特位传递选项2.2 文件相关系统调用2.3 文件操作接口的使用 三、文件描述符fd1.什么是文件描述符2.文件描述符的分配规则 一、文件相关基础知识 我们对文件有如下的认识&#xff1a; 1.文件 …

java设计模式学习之【建造者模式】

文章目录 引言建造者模式简介定义与用途实现方式&#xff1a; 使用场景优势与劣势建造者模式在spring中的应用CD&#xff08;光盘&#xff09;的模拟示例UML 订单系统的模拟示例UML 代码地址 引言 建造者模式在创建复杂对象时展现出其强大的能力&#xff0c;特别是当这些对象需…

带大家做一个,易上手的家常炒鸡蛋

想做这道菜 先准备五个鸡蛋 然后将鸡蛋打到碗里面 然后 加小半勺盐 这个看个人喜好 放多少都没问题 不要太咸就好 将鸡蛋搅拌均匀 起锅烧油 油温热了之后 放三个干辣椒进去炒 干辣椒烧黑后 捞出来 味道就留在油里了 然后 倒入鸡蛋液 翻炒 注意翻炒 不要粘锅底 或者 一面糊…

嵌入式Linux:ARM驱动+QT应用+OpenCV人脸识别项目实现

一、前言&#xff1a; 这个项目主要分为两部分&#xff0c;客户端&#xff08;ARM板端&#xff09;负责利用OpenCV采集人脸数据&#xff0c;利用TCP将人脸数据发送给服务器&#xff0c;然后服务器根据人脸数据进行人脸识别&#xff0c;将识别后的结果返还给客户端&#xff0c;客…

【Linux】环境变量

文章目录 1. 环境变量的概念2. 常见的环境变量3. 查看环境变量的方法4. 测试PATH5. 和环境变量有关的命令6. 环境变量的组织方式7. 通过代码获取环境变量7.1 通过命令行的第三个参数7.2 通过第三方变量environ 8. 通过系统调用获取9. 环境变量的全局属性 1. 环境变量的概念 **…

函数指针数组指针数组传参的本质字符指针(进阶篇)

&#x1f680; 作者&#xff1a;阿辉不一般 &#x1f680; 你说呢&#xff1a;不服输的你&#xff0c;他们拿什么赢 &#x1f680; 专栏&#xff1a;爱上C语言 &#x1f680;作图工具&#xff1a;draw.io(免费开源的作图网站) 如果觉得文章对你有帮助的话&#xff0c;还请点赞…

【带头学C++】----- 八、C++面向对象编程 ---- 8.5 struct结构体类型增强使用说明

目录 8.5 struct结构体类型增强使用说明 8.5.1 C结构体可以定义成员函数 8.5.2 c中定义结构体变量可以不加struct关键字 8.6 bool布尔类型关键字 8.5 struct结构体类型增强使用说明 第六章对结构体的使用、内存对齐以及数组、深拷贝和浅拷贝进行了一个详细的说明&#xff0c…

带键扫的LED专用驱动方案

一、基本概述 TM1650 是一种带键盘扫描接口的LED&#xff08;发光二极管显示器&#xff09;驱动控制专用电路。内部集成有MCU输入输出控制数字接口、数据锁存器、LED 驱动、键盘扫描、辉度调节等电路。TM1650 性能稳定、质量可靠、抗干扰能力强&#xff0c;可适用于24 小时长期…

对抗产品团队中的认知偏误:给产品经理的专家建议

今天的产品经理面临着独特的挑战。他们不仅需要设计和构建创新功能&#xff0c;还必须了解这些功能将如何为客户带来价值并推进关键业务目标。如果不加以控制&#xff0c;认知偏差可能会导致您构建的内容与客户想要的内容或业务需求之间不一致。本文将详细阐述产品经理可以避免…

【EI会议征稿】第四届应用数学、建模与智能计算国际学术会议(CAMMIC 2024)

第四届应用数学、建模与智能计算国际学术会议&#xff08;CAMMIC 2024&#xff09; 2024 4th International Conference on Applied Mathematics, Modelling and Intelligent Computing 第四届应用数学、建模与智能计算国际学术会议&#xff08;CAMMIC 2024&#xff09;将于…

超详细!Opencv人脸识别!附源码!

一、新建环境 注意&#xff01;&#xff01;确定后需要关闭项目&#xff0c;重新打开&#xff0c;终端的环境才会变化&#xff01;&#xff01; 二、下载安装包&#xff08;只需要3个即可&#xff09; 1. 下载dlib包 pip install dlib-19.19.0-cp38-cp38-win_amd64.whl.whl …

XTU OJ 1339 Interprime 学习笔记

链接 传送门 代码 #include<bits/stdc.h> using namespace std;const int N1e610; //78498 我计算了一下&#xff0c;6个0的范围内有这么多个素数&#xff0c;所以开这么大的数组存素数 //计算的代码是一个循环 int prime[80000]; int a[N],s[N];//s数组是前缀和数组b…

力扣 --- 删除有序数组中的重复项 II

题目描述&#xff1a; 给你一个有序数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使得出现次数超过两次的元素只出现两次 &#xff0c;返回删除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的…