【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;
       else
           return 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。

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

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

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

相关文章

从0开始搭建若依微服务项目 RuoYi-Cloud(保姆式教程完结)

文章接上一章&#xff1a; 从0开始搭建若依微服务项目 RuoYi-Cloud&#xff08;保姆式教程 一&#xff09;-CSDN博客 四. 项目配置与启动 当上面环境全部准备好之后&#xff0c;接下来就是项目配置。需要将项目相关配置修改成当前相关环境。 数据库配置 新建数据库&#xff…

布局技巧及CSS初始化

一&#xff0c;margin负值巧妙应用 二&#xff0c;文字围绕浮动元素 三&#xff0c;行内块 四&#xff0c;CSS三角强化 五&#xff0c;CSS初始化 一&#xff0c;margin负值巧妙应用 制作盒子的细线边框&#xff1a; 鼠标经过li后变色&#xff1a; 二&#xff0c;文字围绕…

【单片机】使用AD2S1210旋变芯片读取转子位置和速度

最近在做单片机的子项目&#xff0c;经过近半个月的安装调试&#xff0c;第一阶段顺利完成了。只能说第一次做这种小工程确实缺乏经验&#xff0c;跟书本上学的还是有些出入。做下记录&#xff0c;方便后面来查看。 0. 实验要求 基于STM32单片机&#xff0c;使用AD2S1210旋变芯…

布局管理和样式表

目录 手动操作 相关功能解释&#xff1a; Qt Designer或者QC中的Spacer控件及其属性 网格布局 代码操作 setFocusPolicy() 如果不进行布局&#xff0c;意味着界面上的东西都是写死的。 当我们进行布局操作之后&#xff0c;控件的位置、大小一般会根据窗口缩放来自动调整。…

视频怎么去掉人声保留背景声?这4个简单方法你一定要知道

视频怎么去掉人声保留背景声&#xff1f;在日常生活中&#xff0c;我们经常会遇到需要将视频中的声音去除&#xff0c;尤其是要去掉人声而保留背景声音。这不仅在处理个人视频时非常有用&#xff0c;对于许多专业的视频编辑工作来说也是必不可少的。本文将为你介绍4个简单的方法…

RabbitMQ入门概念

目录 一、RabbitMQ入门 1.1 rabbitmq是啥&#xff1f; 1.2 应用场景 1.3 AMQP协议与RabbitMQ工作流程 1.4 Docker安装部署RabbitMQ 二、SpringBoot连接MQ配置 2.1 示例1 2.1 示例2 —— 发送实体 一、RabbitMQ入门 1.1 rabbitmq是啥&#xff1f; MQ&#xff08;Message…

solidworks 焊接型材库

型材库中有大部分型材 H型钢有49种 八角钢有40种 扁钢有60种 不等边钢有84种 槽钢有41种 也可以按照自己需要的去添加 下载地址https://download.csdn.net/download/jintaihu/19347986

opencv——将2张图片合并

效果演示: 带有绿幕的图片的狮子提取出来,放到另一种风景图片里! 1. 首先我们要先口出绿色绿幕,比如: 这里将绿色绿色绿幕先转为HSV,通过修改颜色的明暗度,抠出狮子的轮廓。 代码 : import cv2 as cv import numpy as np import matplotlib.pyplot as plt def showI…

3671系列矢量网络分析仪

01 3671系列矢量网络分析仪 产品综述&#xff1a; 3671系列矢量网络分析仪产品包括3671C&#xff08;100kHz&#xff5e;14GHz&#xff09;、3671D&#xff08;100kHz&#xff5e;20GHz&#xff09;、3671E&#xff08;100kHz&#xff5e;26.5GHz&#xff09;、3671G&#x…

幻兽帕鲁服务器多少钱?幻兽帕鲁服务器价格,2月最新

2024年幻兽帕鲁服务器价格表更新&#xff0c;阿里云、腾讯云和华为云Palworld服务器报价大全&#xff0c;4核16G幻兽帕鲁专用服务器阿里云26元、腾讯云32元、华为云26元&#xff0c;阿腾云atengyun.com分享幻兽帕鲁服务器优惠价格表&#xff0c;多配置报价&#xff1a; 幻兽帕鲁…

(HAL)STM32F407ZGT6——10-4 高级定时器 PWM 输入模式实验

一、高级定时器简介 高级定时器的框图和通用定时器框图很类似&#xff0c;只是添加了其它的一些功能&#xff0c;如&#xff1a;重复计数器、带死区控制的互补输出通道、断路输入等。 高级定时器的时钟来自APB2, 而PCLK2 168Mhz, 我们设置PPRE2不分频, 因此高级定时器时钟 …

RTC实时时钟之读取时间

1. RTC 基本介绍 RTC(Real Time Clock) 即实时时钟&#xff0c;它是一个可以为系统提供精确的时间基准的元器件&#xff0c;RTC一般采用精度较高的晶振作为时钟源&#xff0c;有些RTC为了在主电源掉电时还可以工作&#xff0c;需要外加电池供电 2. RTC 控制器 2.1 RTC的特点是:…

NC248:左叶子之和(C++)

1.题目描述 2.题目分析 我们以一个二叉树为例 左叶子的特点是什么&#xff1f; 是左节点并且没有左右孩子节点 所以我们用leftnode保存root->lefe节点&#xff0c;判断条件为leftnode存在&#xff0c;并且不存在leftnode->left和leftnode->right&#xff0c;如果满…

[力扣 Hot100]Day18 矩阵置零

题目描述 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 出处 思路 在原数组上直接操作势必会出现“冗余”的0&#xff0c;即原本[i,j]处不是0&#xff0c;例如由于i行的其他位置有0导致[i,j]…

Kali Linux初识

Kali Linux&#xff08;以前称为 BackTrack Linux&#xff09;是一个开源的、基于 Debian 的 Linux 发行版&#xff0c;旨在进行高级渗透测试和安全审计。它通过提供通用工具、配置和自动化来做到这一点&#xff0c;使用户能够专注于需要完成的任务。 包括 600 多种渗透测试工…

LeetCode 使循环数组所有元素相等的最少秒数

地址&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 难度&#xff1a;中等 题目描述&#xff1a;给你一个下标从 0 开始长度为 n 的数组 nums 。 每一秒&#xff0c;你可以对数组执行以下操作&#xff1a; 对于范围在 [0, n - 1] 内的每…

【中关村开源生态论坛暨大模型智能应用技术大会】—— 探索AI和开源在未来的应用

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-9ttR7rpX3BzyF2C4 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

任务悬赏系统搭建开发定制,任务分销系统

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、任务悬赏系统功能和运营方式 总结 前言 任务悬赏系统就是在小程序内可以做任务赚取佣金&#xff0c;这款系统主要针对手上有达人资源的用户可以冲一下这个项目…

(自用)learnOpenGL学习总结-高级OpenGL-几何着色器

在顶点着色器和片段着色器中间还有一个几何着色器。 几何着色器的输入是一个图元的一组顶点&#xff0c;在几何着色器中进行任意变换之后再给片段着色器&#xff0c;可以变成完全不一样的图元、可以生成更多的顶点。 #version 330 core layout (points) in; layout (line_str…

MySql 慢SQL配置,查询,处理

一.慢SQL配置相关 1.查看慢SQL是否开启 执行下面命令查看是否开启慢SQL show variables like %slow_query_log; 复制代码 OFF: 未开启ON: 2.打开慢SQL配置 执行下面的命令开启慢查询日志 set global slow_query_logON; 复制代码 3.修改慢查询阈值 前面介绍了SQL执行到达了…