【Linux】—— 命名管道详解

命名管道是一种在操作系统中用于进程间通信的机制,它允许不同的进程之间通过管道进行数据交换。与匿名管道相比,命名管道具有更多的灵活性和功能。在本博客中,我们将深入探讨命名管道的概念、用途以及如何在编程中使用它们。

目录

(一)什么是命名管道

(二)命名管道原理理解

2.1 创建一个命名管道

2.2 命名管道原理

(三)代码示例

3.1命名管道的打开规则

3.2 实现server&client通信 

 (四)小结


(一)什么是命名管道

命名管道是一种具有独特标识符(通常是文件路径)的管道。它允许不同进程通过该标识符进行通信。与无名管道不同,命名管道存在于文件系统中,使得它们能够跨越进程和甚至计算机边界进行通信。

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

(二)命名管道原理理解

2.1 创建一个命名管道

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

mkfifo filename
  • 我们不了解的话可以通过man手册去对这个函数进行学习: 

 示例演示:

【解释说明】 

  • 我们可以先手动的创建一个管道文件,给它起一个 fifo 的文件名,创建好之后我们就看到了当前目录下存在了一个文件叫做 fifo ;
  • 其次我们可以发现它的文件类型前面以P开头,当大家看到P开头的,会能想到什么?在之前我给大家在讲我们Linux基础命令的时候说过一个话题叫做文件类型:以 - 开头普通文件、以D开头为目录文件、以L开头为链接文件L开头的叫做软链接、这里以P开头叫做管道文件,这时候在磁盘上存在了一个管道文件

  接下来,我准备向文件中写入数据:

【解释说明】  

  • 在我们的理解中把它写到文件当中,此时就相当于当我一敲回车,echo对应的这个东西就会变成进程;
  • 然后,执行我们向显示器当中打印,经过重定向,它最终不向显示器文件打印,而向管道文件中打印,所以底层作为重定向是没问题的;
  • 紧接着我们就尝试去写了,但当前呢它卡在这里的,什么都没做,我们再看一下当前这个管道文件里,当前显示的是零,好像没有写入啊;
  • 这是因为管道文件有种特殊特性,虽然在磁盘当中创建了这个 fifo,但它仅仅是一种符号,那么对于这种符号呢,将来你向这个文件里写入的消息,并没有或者并不会刷新落实到磁盘上,而是只帮我们在这里直接 echo,然后写入管道文件当中,但是管道文件当前是内存级的,所以你的大小没有变。

接下来,我们在尝试一下输出重定向操作:

 【解释说明】  

  • 对于 cat 指令默认就是从显示器当中进行读取,你输什么它给你打印什么;
  • cat fifo 可以直接从管道文件当中输出重对象,将曾经他向管道里写的东西写到它里面;
  • 另外cat也是一条命令,它一旦启动就会变成进程,所以这是一个进程,这俩进程没有任何关系,然后我们这个hello world 的消息最终就打印了出来,这种通讯方式我们就称之为叫做命名管道。

 接下来,我再改一下代码逻辑,再给大家分析一波:

【解释说明】

  • 在进行显示的时候,我让它每隔一秒进行向我们显示器当中打印一条hello world;
  • 但我不想往显示器打印,我想让往管道打印,此时上述那一堆就对应的一个进程,向我们对应的管道文件当中写入;
  • 那么对于 fifo 此时呢,我们就看到本来应该显示到这个显示器文件这个终端的字符串,最终经过管道被重定向到了右端。

2️⃣ 命名管道也可以从程序里创建,相关函数有:

int mkfifo(const char *filename,mode_t mode);

2.2 命名管道原理

【解释说明】 

  • 现在假设左边框框里,它是我们对应的操作系统内部的一大堆的数据结构,和它对应的磁盘组成;
  • 如果磁盘里有一个文件,现在有一个问题,如果我有一个进程要打开它,这是个进程,打开一个文件,有自己的文件描述符表,然后012定义的是标准输入标准输出标准错误这;
  • 此时,对应的要打开我们对应的这个文件,怎么打开呢?我曾经讲过一个文件如果不打开,它就在磁盘上静静的躺着,就有了我们之前讲的分区,然后格式化,然后有文件系统等;
  • 紧接着,对应的这个磁盘文件,它里面还可以去包含文件相关的属性inode,还有它对应的缓冲区等等,一旦它被打开了,首先要在操作系统内为该文件创建对应的struct file对象,然后这个struct file对象它有对应的自己的缓冲区;
  • 在结构体当中,有指针指向它的缓冲区,实际上它里面严格上讲应该是指向它inode,然后进一步指向缓冲区

【解释说明】  

  •  我们让父进程创建子进程的时候,子进程会继承父进程的文件描述符表;
  • 所以对于子进程,它直接继承父进程的文件描表之后,它会把这个值拷下来,拷下来之后,他俩就指向同一个文件了;

 上诉是第一种情况,假设如果又来了一个进程,他也要有自己的文件描述符表,紧接着有一个小问题?

  • 如果这个进程此时也打开磁盘中的这个文件了,还用不用再在操作系统内部给他创建一个对应的struct file 结构体,然后给他创建一个缓冲区,然后这样去搞呢?

【解释说明】 

  •  其实大可不必;
  • 因为在正常的情况下,对应的文件的属性的值呢数字是一样的,所以操作系统内根本就不需要维护对应的两个一样的结构体;

【解释说明】  

  •  所以对于我们来讲,实际上当你想打开这个文件时,当新进程想打开其他文件时,新进程先做的第一件事情是在所有已经打开的文件列表里去找这个文件是否已经被打开了,没有被打开则创建,如果已经打开了;
  • 直接把对应的我们struct file对象的地址填入到对应的下标里,而对应的这个struct file对象里面包含一个叫做ref,我们称之为引用计数;
  • 这个引用计数指向的时候,默认是1,再有进程打开它就变成2了,当你关闭这个文件时,它就把这个ref进行减减操作,由2再变成对应的1,当你再关闭它才由1变成0,然后操作系统才释放它。

【注意事项】

不过如果这个文件是一个普通文件,将来你写的时候数据要定期刷新到磁盘里面,可是今天我们的目的是想让这两个进程,通过对应的缓冲区让他们俩之间通信,好让他们俩直接通信,那么我们的文件呢就不应该把这个数据刷到磁盘上,所以未来呢,我们如果创建了一个文件,这种文件必须有一个特性,就叫做是内存级

 【解释说明】  

  •  也就是说对于这种文件只需要把数据有一个进程写进来,另一个进程再从缓冲区中读,此时不需要做这个刷盘动作;
  • 如果做了刷盘操作:一导致速度慢了,二也没必要,所以我们就由此诞生了一种文件,这种文件就叫做管道文件,或者叫做命名管道文件,它就是一个文件,只不过这个文件呢,没有所谓的data block,它就是在磁盘当中的一种

(三)代码示例

3.1命名管道的打开规则

如果当前打开操作是为而打开FIFO时

  • O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO
  • O_NONBLOCK enable:立刻返回成功

如果当前打开操作是为而打开FIFO时

  • O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO
  • O_NONBLOCK enable:立刻返回失败,错误码为ENXIO
     

3.2 实现server&client通信
 

【client.cc】

#include <iostream>
#include <cstdio>
#include <cerrno>
#include <cstring>
#include <cassert>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "common.hpp"int main()
{//1. 不需创建管道文件,我只需要打开对应的文件即可!int wfd = open(fifoname.c_str(),O_WRONLY);if(wfd < 0){std::cerr << errno << ":" << strerror(errno) << std::endl;return 1;}//正常通信char buffer[NUM];while(true){system("stty raw");int c = getchar();system("stty -raw");ssize_t n = write(wfd, (char*)&c, sizeof(char));assert(n >= 0);(void)n;}//关闭不要的fdclose(wfd);return 0;
}

【server.cc】

#include <iostream>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "common.hpp"int main()
{// 1. 创建管道文件umask(0); //这个设置并不影响系统的默认配置,只会影响当前进程int n = mkfifo(fifoname.c_str(),mode);if(n != 0){std::cout << errno << " : " << strerror(errno) << std::endl;return 1;}std::cout << "create fifo file success" << std::endl;// 2.让服务端直接开启管道文件int rfd = open(fifoname.c_str(), O_RDONLY);if(rfd < 0 ){std::cout << errno << " : " << strerror(errno) << std::endl;return 2;}std::cout << "open fifo success" << std::endl;// 3.正常通信char buffer[NUM];while (true){buffer[0] = 0;ssize_t n = read(rfd,buffer,sizeof(buffer));if(n > 0){buffer[n] = 0;printf("%c", buffer[0]);fflush(stdout);}else if(n == 0){std::cout << "client quit, me too" << std::endl;break;}else {std::cout << errno << " : " << strerror(errno) << std::endl;break;}}// 4.关闭不要的fdclose(rfd);unlink(fifoname.c_str());return 0;
}

【common.hpp】

#pragma once#include <iostream>
#include <string>#define NUM 1024const std::string fifoname = "./fifo";
uint32_t mode = 0666; 

 (四)小结

以上便是关于命名管道的全部知识内容了,接下来简单小结命名管道以及匿名管道和命名管道之间的区别!!

 命名管道:

  1. 基本概念: 命名管道是一种通过文件系统路径标识的通信管道,允许不同进程之间进行通信。

  2. 创建方式: 在Unix/Linux系统中,可以使用 mkfifo 函数创建命名管道;在Windows系统中,可以使用 CreateNamedPipe 函数。

  3. 通信方向: 命名管道同样是单向的,但可以被用于任意两个进程之间的通信,甚至是不同计算机之间。

  4. 生命周期: 命名管道的生命周期不受限于创建它的进程,可以长时间存在于文件系统中。

  5. 灵活性: 命名管道相对于匿名管道更灵活,适用于更复杂的进程通信场景,包括跨越进程和计算机的通信。

匿名管道与命名管道的区别:

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

本文内容便讲解结束,感谢大家的观看和支持!! 

 

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pycharm创建vue项目idealTree:npm: sill idealTree buildDeps,换taobao源后还不好使?那就再换一个

心血来潮打算写个小项目&#xff0c;前后端分离&#xff0c;flask/fastapivue&#xff08;具体用哪个后端还没想好&#xff09;&#xff0c;里面的功能大概就是目前所有热门的应用的合集&#xff0c;一键出结果的那种&#xff0c;然后跟随着科技趋势&#xff0c;不断去更新维护…

实现钉钉与宁波银行对接,助力东吴黄金集团财务智能化

客户介绍&#xff1a; 某黄金集团有限公司是一家在国内外黄金市场上具有重要影响力的综合性黄金企业。该公司拥有一支高素质、专业化的团队&#xff0c;具备丰富的行业经验和卓越的执行力。在业务范围上&#xff0c;该公司涵盖了黄金勘探、采选、冶炼、加工、销售等全产业链&a…

C#使用DateAndTime.DateDiff方法计算年龄

目录 一、计算年龄的方法 二、 DateAndTime类 1.定义 2.常用方法 3.DateDiff(DateInterval, DateTime, DateTime, FirstDayOfWeek, FirstWeekOfYear) 三、使用DateAndTime.DateDiff方法计算年龄 一、计算年龄的方法 使用DateDiff方法计算系统时间与员工生日之间相隔的年…

【机器学习:异常值检测】新颖性和异常值检测

【机器学习&#xff1a;异常值检测】新颖性和异常值检测 异常值检测方法概述新颖性检测纵向扩展单类 SVM 异常值检测拟合椭圆包络隔离林局部异常因子使用局部异常因子进行新颖性检测 许多应用程序需要能够确定新观测值是属于与现有观测值相同的分布&#xff08;它是异常值&…

【算法练习Day51】柱状图中最大的矩形

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 柱状图中最大的矩形思路动态…

【C++】初识类和对象

引言 在C语言中&#xff0c;我们用结构体来描述一个复杂的对象&#xff0c;这个对象可能包括许多的成员&#xff0c;如用结构体描述一个学生的成绩&#xff0c;或者描述一个日期等。 struct Date {int _year;int _month;int _day; }; 如上是一个描述日期的结构体定义&#x…

不同业务模式的跨境电商如何借助云桥通SDWAN组网做Tiktok生意?

TikTok for Business的出海电商行业运营策略负责人在演讲中强调&#xff0c;商家在TikTok实现销售的两种主要方法包括开设TikTokShop和利用各类广告产品引流到独立站。在TikTokShop开店的过程中&#xff0c;商家需完成入驻、学习运营指南、通过新店铺考察期等步骤。而利用广告引…

HYBBS 表白墙网站PHP程序源码 可封装成APP

源码介绍 PHP表白墙网站源码&#xff0c;可以做校园内的&#xff0c;也可以做校区间的&#xff0c;可封装成APP。告别QQ空间的表白墙吧。 安装PHP5.6以上随意 上传程序安装&#xff0c;然后设置账号密码&#xff0c;登陆后台切换模板手机PC都要换开启插件访问前台。 安装完…

MySQL---多表分组查询综合练习

创建dept表 CREATE TABLE dept ( deptno INT(2) NOT NULL COMMENT 部门编号, dname VARCHAR (15) COMMENT 部门名称, loc VARCHAR (20) COMMENT 地理位置 ); 添加dept表主键 mysql> alter table dept add primary key(deptno); Query OK, 0 rows affected (0.02 s…

最小生成树(java版)

&#x1f4d1;前言 本文主要是【最小生成树】——最小生成树使用的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每日一…

什么是VUE 创建第一个VUE实例

一、什么是Vue 概念&#xff1a;Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套 构建用户界面 的 渐进式 框架 Vue2官网&#xff1a;Vue.js 1.什么是构建用户界面 基于数据渲染出用户可以看到的界面 2.什么是渐进式 所谓渐进式就是循序渐进&#xff0c;不一定非得把Vu…

从丘成桐、张益唐的超国民待遇,看孙卫东风光回国的可能性

复旦博士孙卫东在美国流浪16年&#xff0c;这事儿最近在国内媒体沸沸扬扬&#xff0c;围绕着是否让孙卫东回国&#xff0c;国民形成了截然对立的两派&#xff1a;一派呼吁帮其回国&#xff0c;认为他身上流着中国人的血、是我们的同胞&#xff1b;另一派则是反对阻止&#xff0…