命名管道:简单案例实现

news2024/11/18 7:35:18

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

🌴专栏链接: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; //打开方式

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

在这里插入图片描述

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

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

相关文章

PHP+ajax+layui实现双重列表的动态绑定

需求&#xff1a;商户下面有若干个门店&#xff0c;每个门店都需要绑定上收款账户 方案一&#xff1a;每个门店下面添加页面&#xff0c;可以选择账户去绑定。&#xff08;难度&#xff1a;简单&#xff09; 方案二&#xff1a;从商户进入&#xff0c;可以自由选择门店&#…

【程序员养生心得】—— 编程之路,健康同行

身为程序员&#xff0c;我们似乎总和亚健康、熬夜、颈椎病等标签紧密相连。但工作虽重要&#xff0c;健康价更高。在此&#xff0c;我想与大家分享一些在编程之路上的养生心得&#xff0c;希望我们都能在职业发展的同时&#xff0c;照顾好自己。 定时休息&#xff0c;活动身体&…

创建SpringBoot流程

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、操作步骤总结 前言 我使用的是jdk1.8版本的&#xff0c;idea社区版的&#xff08;专业版的应该也差不多吧&#xff09; 提示…

leetcode二叉树

下面的两个题呢是比较类似的所以放在一起讲&#xff0c;更好的理解起来。 https://leetcode.cn/problems/same-tree/description/ 这个题就是比较两颗树是不是一样的&#xff0c;这个其实看起来就只要比较当前节点&#xff0c;我们分析成子问题就是判断两颗树当前节点是不是一致…

用HeidiSQL在MySQL中新建用户

用HeidiSQL登录到MySQL数据库&#xff0c;注意登录的时候要使用有权限的用户&#xff1a; 选择工具-》用户管理&#xff1a; 点击左上角的“添加”&#xff1a; 输入用户名、密码&#xff0c;并且分配权限&#xff1a; 点击右边的“添加对象”&#xff1a; 可以根据自己…

使用OpenCompass评测rwkv模型教程

0x0. 前言 继续MLC-LLM 支持RWKV-5推理以及对RWKV-5的一些思考文章里面提到的想法&#xff0c;探索一下使用OpenCompass来评测RWKV模型&#xff0c;对模型的实际表现有一个更客观的了解。我在尝试的过程中也碰到了一些问题&#xff0c;所以这里记录一下使用OpenCompass评测的流…

数据的另一面:数据可视化为何备受推崇?

数据可视化&#xff0c;作为当今信息时代的重要工具&#xff0c;正逐渐受到更多人的关注和重视。它的重要性不仅在于帮助人们更直观地理解数据&#xff0c;更在于为我们揭示数据背后的故事&#xff0c;以及对决策和发现见解的巨大价值。那么&#xff0c;为何数据可视化越来越被…

LeetCode(36)旋转图像【矩阵】【中等】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 48. 旋转图像 1.题目 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在** 原地** 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 …

Nuxt.js:下一代Web开发框架的革命性力量

文章目录 一、Nuxt.js简介二、Nuxt.js的特点1. 集成Vue.js和Node.js2. 自动代码分割和优化3. 服务端渲染&#xff08;SSR&#xff09;4. 强大的路由管理5. 丰富的插件系统 三、Nuxt.js的优势1. 提高开发效率2. 降低维护成本3. 提高用户体验 四、Nuxt.js在实际应用中的案例1. 电…

深兰科技入选工信部首批“5G+智慧旅游”应用试点项目名

近日&#xff0c;国家文旅部与工信部确定并公布了我国首批《“5G智慧旅游”应用试点项目名单》&#xff0c;深兰科技基于AIGC多模态融合大模型技术开发打造的江汉路“5G智慧旅游”试点项目——武汉市江汉路步行街5G智慧商街创新应用&#xff0c;成功入选该名单。 作为由湖北省文…

电脑突然死机怎么办?教你几招快速拯救

当今社会&#xff0c;电脑成为我们日常生活和工作不可或缺的一部分。然而&#xff0c;有时电脑可能会突然死机&#xff0c;给我们的操作和数据带来不便。那电脑突然死机怎么办呢&#xff1f;本文将介绍解决电脑突然死机的三种方法&#xff0c;通过详细的步骤指南&#xff0c;帮…

SaaS模式C/S检验科LIS系统源码

适用于医院检验科实际需要的管理系统, 实现检验业务全流程的计算机管理。从检验申请、标本编号、联机采集、中文报告单的生成与打印、质控图的绘制和数据的检索与备份。通过将所有仪器自身提供的端口与科室LIS系统中的工作站点连接,实现与医院HIS系统的对接。 通过门诊医生和住…

【古月居《ros入门21讲》学习笔记】05_ROS是什么及其核心概念

目录 说明 1. ROS发展史 ROS版本演变 2. ROS是什么 ROS中的通信机制 ROS中的开发工具 ROS中的应用功能 ROS中的生态系统 3. ROS核心概念 节点与节点管理器 通信方式1&#xff1a;话题 通信方式2&#xff1a;服务 话题与服务的区别 参数 文件系统 说明 1. 本系列…

智能优化算法应用:基于帝国主义竞争算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于帝国主义竞争算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于帝国主义竞争算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.帝国主义竞争算法4.实验参数设定5.算…

php爬虫实现把目标页面变成自己的网站页面

最近又被烦的不行&#xff0c;琐事不断&#xff0c;要是比起懒来一个人比一个人懒&#xff0c;但是懒要转换成动力啊&#xff0c;能让自己真正的偷懒&#xff0c;而不是浪费时间。每天还是需要不断的学习的&#xff0c;才能更好的提高效率&#xff0c;把之前做的简单小功能爬虫…

计算机网络(一)| 概述 因特网 性能 协议基本

文章目录 1. 因特网组成1.1 四元素组成1.2 二元素组成1.3 核心部分 2.计算机网路的功能3. 几种不同类别的网络4 性能指标5 网路协议5.1网络体系结构 6 PDU 互联网&#xff08;或因特网&#xff09;之所以能够向用户提供服务&#xff0c;是因为互联网具有两个重要基本特点 连通性…

Wireshark之Intro, HTTP, DNS

源码地址&#x1f447; moranzcw/Computer-Networking-A-Top-Down-Approach-NOTES: 《计算机网络&#xff0d;自顶向下方法(原书第6版)》编程作业&#xff0c;Wireshark实验文档的翻译和解答。 (github.com) 目录 &#x1f33c;Introduce &#x1f3a7;前置 &#x1f3a7;过…

java:IDEA中Maven常用操作

文章目录 背景1、Reload All Maven Projects:2、Generate Sources and Update Folders For All Projects:3、Download Sources and/or Documentation:4、Add Maven Projects5、Run Maven Build6、Execute Maven Goal7、Toggle Offline Mode8、Toggle Skip Tests Mode9、Collaps…

10分钟的时间,带你彻底搞懂JavaScript数据类型转换

前言 &#x1f4eb; 大家好&#xff0c;我是南木元元&#xff0c;热衷分享有趣实用的文章&#xff0c;希望大家多多支持&#xff0c;一起进步&#xff01; &#x1f345; 个人主页&#xff1a;南木元元 目录 JS数据类型 3种转换类型 ToBoolean ToString ToNumber 对象转原…

Go语言多线程爬虫万能模板:实现高效数据采集

随着互联网的快速发展&#xff0c;网络爬虫已经成为数据采集的重要工具。Go语言作为高性能编程语言之一&#xff0c;具有出色的并发性能和丰富的网络库&#xff0c;非常适合用于编写多线程爬虫。本文将介绍一个基于Go语言的多线程爬虫万能模板&#xff0c;并阐述其设计思路、核…