【Linux】命名管道

文章目录

  • 命名管道
      • 一、命名管道的原理
      • 二、命名管道的创建
          • 命令行中创建
          • 程序中创建 - mkfifo函数:
      • 三、命名管道的使用
          • 命名管道实现server&client通信
      • 四、匿名管道与命名管道的区别和联系

命名管道

如果涉及到在文件系统中创建一个有名的管道,那么就是在使用命名管道。

一、命名管道的原理

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

注意:
普通文件是很难做到通信的,即便做到通信也无法解决一些安全问题。
命名管道和匿名管道一样,都是内存文件,只不过命名管道在磁盘有一个简单的映像,但这个映像的大小永远为0,因为命名管道和匿名管道都不会将通信数据刷新到磁盘当中。

二、命名管道的创建

命令行中创建

在命令行中,可以使用mkfifo命令创建命名管道。mkfifo命令的语法如下:

mkfifo [OPTION]... NAME...

其中,OPTION是可选的参数,而NAME是要创建的命名管道的名称。以下是一个简单的示例:

mkfifo fifo

请添加图片描述

这会在当前目录下创建一个名为 fifo 的命名管道。命名管道的创建后,可以像文件一样对待,可以通过其他命令或程序来读取和写入,但是。

程序中创建 - mkfifo函数:

mkfifo函数是一个库函数,它是由C标准库提供的,而不是直接调用底层操作系统的系统调用。在C语言中,可以使用mkfifo系统调用来在程序中创建命名管道。该系统调用的函数原型如下:

#include <sys/types.h>
#include <sys/stat.h>int mkfifo(const char *pathname, mode_t mode);
  • pathname 参数是命名管道的路径和名称。
  • mode 参数是权限位,用于指定文件权限。
    当然,实际上创建出来文件的权限值还会受到umask(文件默认掩码)的影响,实际创建出来文件的权限为:mode&(~umask)。umask的默认值一般为0002,如果我们设置mode值为0666时,则实际创建出来文件的权限为0664。

三、命名管道的使用

命名管道实现server&client通信

实现服务端(server)和客户端(client)之间的通信之前,我们需要先让服务端运行起来,让服务端运行后创建一个命名管道文件,然后客户端再以读的方式打开该命名管道文件,之后服务端就可以从该命名管道当中读取客户端发来的通信信息了。

服务端的代码,server.cpp 如下:

#include "comm.h"using namespace std;int main()
{int n = mkfifo(FILENAME, 0666);if (n < 0){cerr << "mkfifo failed, errno: " << errno << ", errstring:" << strerror(errno) << endl;return 1;}cout << "mkfifo success..." << endl;int rfd = open(FILENAME, O_RDONLY);if (rfd < 0){cerr << "errno: " << errno << ", errstring:" << strerror(errno) << endl;return 2;}cout << "open fifo success..." << endl;char buffer[1024];while (true){ssize_t s = read(rfd, buffer, sizeof(buffer) - 1);if (s > 0){buffer[s] = '\0';cout << "Client say# " << buffer << endl;}}close(rfd);cout << "close fifo success..." << endl;return 0;
}

客户端的代码,如下:

#include "comm.h"using namespace std;int main()
{int wfd = open(FILENAME, O_WRONLY);if (wfd < 0){cerr << "errno: " << errno << ", errstring:" << strerror(errno) << endl;return 1;}string message;while (true){cout << "Please Enter# ";getline(cin, message);ssize_t s = write(wfd, message.c_str(), message.size());if (s < 0){cerr << "errno: " << errno << ", errstring:" << strerror(errno) << endl;return 2;}}close(wfd);std::cout << "close fifo success..." << std::endl;return 0;
}

让客户端和服务端包含同一个头文件,该头文件当中提供这个共用的命名管道文件的文件名和共用的头文件。

// comm.h
#pragma once#include <cerrno>
#include <cstdio>
#include <string>
#include <iostream>
#include <cstring>#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>#define FILENAME "myfifo" //让客户端和服务端使用同一个命名管道

先将服务端进程运行起来,之后我们就能在客户端看到这个已经被创建的命名管道文件:
请添加图片描述

请添加图片描述

使用ps axj搭配grep来查询这两个进程:

ps axj | head -1 && ps axj| grep -E '\./server|\./client' | grep -v grep

请添加图片描述

发现这两个进程确实是两个毫不相关的进程,因为它们的PID和PPID都不相同。也就证明了,命名管道是可以实现两个毫不相关进程之间的通信的。

有个小问题是,如果跑完一次想要再运行,命名管道文件mypipe还依然存在,会引发报错程序直接退出:
请添加图片描述


优化一下server.cpp:

#include "comm.h"using namespace std;bool MakeFifo()
{int n = mkfifo(FILENAME, 0666);if (n < 0){cerr << "mkfifo failed, errno: " << errno << ", errstring:" << strerror(errno) << endl;return false;}cout << "mkfifo success..." << endl;return true;
}int main()
{
Start:int rfd = open(FILENAME, O_RDONLY);if (rfd < 0) // 优化:如果open失败,就创建fifo管道文件,然后回到start再open{cerr << "errno: " << errno << ", errstring:" << strerror(errno) << endl;if (MakeFifo())goto Start;elsereturn 1;}cout << "open fifo success..." << endl;char buffer[1024];while (true){ssize_t s = read(rfd, buffer, sizeof(buffer) - 1);if (s > 0){buffer[s] = '\0';cout << "Client say# " << buffer << endl;}}close(rfd);cout << "close fifo success..." << endl;return 0;
}

四、匿名管道与命名管道的区别和联系

谈区别之前,先提一下系统调用 openreadwrite 等系统调用,它们对于这两种管道都有几乎相同的行为,可能会发生阻塞等待的情况如下:

  1. open系统调用:

    • 打开管道的读端或写端时,如果另一端尚未被打开,打开调用可能会阻塞等待。
    • 当打开读端时,通常期望有其他进程打开相应的写端,否则读端打开可能会一直阻塞,直到写端被打开。
    • 当打开写端时,通常期望有其他进程打开相应的读端,否则写端打开可能会一直阻塞,直到读端被打开。
  2. read系统调用:

    • 当从管道中读取数据时,如果管道为空,read 调用可能会阻塞等待,直到有数据可读。
    • 如果管道的写端已经关闭,并且没有数据可供读取,read 调用将返回0,表示已经读到了文件末尾(EOF)。
  3. write系统调用:

    • 当向管道中写入数据时,如果管道满了,write 调用可能会阻塞等待,直到有空间可写。
    • 如果管道的读端已经关闭,而且没有进程读取数据,write 调用可能会导致信号 SIGPIPE 被发送给写入进程。

梳理两种管道的区别:

FIFO(命名管道)与pipe(匿名管道)之间最大的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义。

  1. 匿名管道(Anonymous Pipe):

    • 匿名管道是通过调用 pipe 函数创建的,通常用于父子进程之间的通信。
    • 匿名管道没有文件系统中的名字,只能用于相关进程之间的通信。
    • 读端和写端的打开行为以及数据的传输与上述描述一致。
    • 当读取所有数据后,进程试图继续读取时,read 返回0,表示已经读到了文件末尾(EOF)。
  2. 命名管道(Named Pipe,Linux下称为FIFO):

    • 命名管道是通过调用 mkfifo 函数创建的,通常用于无关联进程之间的通信。
    • 命名管道在文件系统中有一个名字,可以被多个进程通过这个名字进行访问。
    • openreadwrite 等系统调用的行为与上述描述基本一致。
    • 与匿名管道相似,当读取所有数据后,进程试图继续读取时,read 返回0。

需要注意,对于命名管道,当所有写端都被关闭而读端仍然打开时,后续的读取操作可能会阻塞等待。这是因为当所有写入端关闭后,读取端可能仍在等待写入端的数据,直到有新的数据写入或者读取端被关闭。这与匿名管道有些许不同。

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

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

相关文章

HarmonyOS模拟器启动失败,电脑蓝屏解决办法

1、在Tool->Device Manager管理界面中&#xff0c;通过Wipe User Data清理模拟器用户数据&#xff0c;然后重启模拟器&#xff1b;如果该方法无效&#xff0c;需要Delete删除已创建的Local Emulater。 2、在Tool->SDK Manager管理界面的PlatForm选项卡中&#xff0c;取消…

C++11—— lambda表达式与包装器

C11—— lambda表达式与包装器 文章目录 C11—— lambda表达式与包装器一、 lambda表达式lambda表达式产生的意义lambda表达式语法函数对象与lambda表达式 二、 包装器functionfunction产生的意义function的用法function使用的例子 bind调整参数顺序固定绑定参数 一、 lambda表…

Redis常用数据结构与应用场景

常用数据结构 StringHashListSetZset String常用操作 String应用场景 Hash常用操作 hash应用场景 Hash结构优缺点 优点 同类数据归类整合存储,方便数据管理相比String操作消耗内存与spu更小相比string更节省空间 缺点 过期功能不能使用在field上,只用用在key上Redis集群…

TypeScript实战系列之合理运用类型

目录 介绍any 和 unknownerve 的用途断言type 和 interfacedeclare 关键字的作用联合类型 和 类型守卫交叉类型 介绍 这篇主要介绍下ts 常用的基本类型和一些常用的技巧性技能 any 和 unknow any 和 unknown 是两个类型关键字&#xff0c;它们用于处理类型不确定或未知的情况…

yolov8数据标注、模型训练到模型部署全过程

文章目录 一、数据标注&#xff08;x-anylabeling&#xff09;1. 安装方式1.1 直接通过Releases安装1.2 clone源码后采用终端运行 2. 如何使用 二、模型训练三、模型部署3.1 onnx转engine3.2 c调用engine模型3.2.1 main_tensorRT.cpp3.2.2 segmentationModel.cpp 一、数据标注&…

爱可声助听器参与南湖区价值百万公益助残捐赠活动成功举行

“声音大小合适吗&#xff1f;能听清楚吗&#xff1f;”今天下午&#xff0c;一场助残捐赠活动在南湖区凤桥镇悄然举行&#xff0c;杭州爱听科技有限公司带着验配团队和听力检测设备来到活动现场&#xff0c;为南湖区听障残疾人和老人适配助听器。 家住余新镇的75岁的周奶奶身体…

1.迭代与递归 - JS

迭代与递归是函数进阶的第一个门槛。迭代就是对已知变量反复赋值变换&#xff1b;递归就是函数体内调用自身。 迭代 一个迭代是就是一个循环&#xff0c;根据迭代式对变量反复赋值。 求近似根&#xff08;切线法&#xff09;&#xff1b; 迭代描述&#xff1a; x 0 x_0 x0…

C语言KR圣经笔记 6.6 表查询 6.7 typedef

6.6 表查询 为了说明结构体的更多方面&#xff0c;本节我们来写一个表查询功能包的内部代码。在宏处理器或编译器的符号表管理例程中&#xff0c;这个代码是很典型的。例如&#xff0c;考虑 #define 语句&#xff0c;当遇到如下行 #define IN 1 时&#xff0c;名称 IN 与其对…

微信小程序如何实现点击上传图片功能

如下所示,实际需求中常常存在需要点击上传图片的功能,上传前显示边框表面图片显示大小,上传后将图形缩放到边框大小。 实现如下: .wxml <view class="{{img_src==?blank-area:}}" style="width:100%;height:40%;display:flex;align-items: center;jus…

spring框架(一)

1、Spring框架&#xff1a;IoC和AOP 服务端三层开发&#xff1a;表现层、业务层、持久层 ssm, springboot, springcloud(微服务&#xff0c;治理组件) Spring框架是一个流行的Java应用程序框架&#xff0c;它提供了许多功能来简化企业级应用程序的开发。其中&#xff0c;控制反…

Selenium 隐藏浏览器指纹特征的几种方式

我们使用 Selenium 对网页进行爬虫时&#xff0c;如果不做任何处理直接进行爬取&#xff0c;会导致很多特征是暴露的 对一些做了反爬的网站&#xff0c;做了特征检测&#xff0c;用来阻止一些恶意爬虫 本篇文章将介绍几种常用的隐藏浏览器指纹特征的方式 1. 直接爬取 目标对…

面试题 02.07. 链表相交(力扣LeetCode)

文章目录 面试题 02.07. 链表相交题目描述解题思路c代码优化后c代码 面试题 02.07. 链表相交 题目描述 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点&#xff0c;返回 null 。 图示两个链表在节点 c1 …

shell

目录 一.运行方式 二.编程习惯 三.变量 3.1变量的命名 3.3普通变量(局部变量) 3.4特殊变量 3.5变量子串 3.6变量赋值 四.运算方式 4.1$(( )) 4.2let 4.3expr 4.4bc(小数运算) 4.5$[ ] 4.6awk 4.7总结运算方式 五.条件测试语句 5.1文件 5.2条件测试表达式…

IDEA:git 回滚本地提交-git 选择 Reset Current Branch to

前言 回滚提交到本地但是还没有 Push 上去的提交 选择我们要回滚的节点&#xff0c;然后点击 git 选择 Reset Current Branch to… 再选择 Hard 。当我们点击 Reset 的时候&#xff0c;代码就会回滚到单前选中的这个版本

数字时代的工作利器

当谈到使用工作软件的多样选择时&#xff0c;就像是探索灯塔下的海洋般令人兴奋。无论是新进入办公领域的小白&#xff0c;还是经验丰富的职场老将&#xff0c;我们都渴望找到那些能在工作中为我们点燃生产力和创造力的魔法工具。下面是五款备受欢迎且富有创造力的工作软件推荐…

专业120+总分400+宁波大学912信号与系统考研经验电子信息通信集成电路光电

今年考研顺利上岸&#xff0c;专业课912信号与系统120&#xff0c;总分400&#xff0c;被宁波大学录取&#xff0c;回望这一年的复习有过迷茫和犹豫&#xff0c;也有过坚持和坚强&#xff0c;总结一下自己的复习得失&#xff0c;希望对大家复习有所帮助。专业课&#xff1a; 前…

【重磅发布】已开放!模型师入驻、转格式再升级、3D展示框架全新玩法…

1月23日&#xff0c;老子云正式发布全新版本。此次新版本包含多板块功能上线和升级&#xff0c;为用户带来了含模型师入驻、三维格式在线转换升级、模型免费增值权益开放、全新3D展示框架等一系列精彩内容&#xff01; 1月23日&#xff0c;老子云正式发布全新版本。此次新版本…

【vue】图片加载骨架

一、前言 在网速较低或者网站的服务器宽带只有几MB的情况下&#xff0c;网页中的图片加载时&#xff0c;要么空白&#xff0c;要么像打印机一样一行一行地“扫描”出来&#xff0c;为了提升用户体验&#xff0c;可以给图片标签外加一层骨架。 无骨架 有骨架 二、详细设计 每张…

现在我有三个代码块,分别都调用了同一个接口使用相同的数据,请问怎么精简代码,让他只调用一次接口,将数据存储起来让其他函数共同使用.

问题描述: 现在我有三个代码块: 一: const getData async () > {console.log(触发了getData接口)let resultData await getActivityInfo(activityId);console.log(resultData,resultData)let id resultData.id;let shareImg resultData.shareImglet shareSubtitle res…

JWT(JSON Web Token)详解以及在go-zero中配置的方法

目的 对用户进行身份认证和信息交换 RFC 7519 传统方式 通过session保存对话信息&#xff0c;服务端返回一个session id&#xff0c;用户保存这个id在cookie内&#xff0c;然后每次请求都传给服务端 局限性 对于服务器集群难以向每个服务器共享同一session jwt的方式是…