Linux小黑板(8)管道

news2024/11/24 16:34:36

"让我们,笑吧"

一、什么是通信?

管道是属于进程间通信的一个实现方式。再讲管道之前呢,我们先来说说什么叫做进程间通信。我们日常生活中,给自己的家人、朋友给一个call,或者弹一条微信、QQ等等,从而让人家能够知道我们想给对方传达的信息是什么,这其实简单来说是一种信息的交互。

(1)为什么需要通信?

进程通信的目的有很多种:
数据传输:一个进程需要将数据发送给另外一个进程。
资源共享:多个进程之间共享同样的资源。
通知事件:一个进程需要向另一个或者另一组进程发送消息,通知它们发生了某种事件。
进程控制:有些进程希望完全控制另外一个进程的执行(如我们进入调试debug)。

比如,我们想在file.txt里查找到hello的字段。命令行中,cat是一个进程,grep也是一个进程。

他们通过"|"管道,进行了数据通信。cat负责打印file.txt中的数据到显示器,grep 负责从这些数据按关键字过滤。从而达到我们想要的效果。那么在个地方,我们使用到了进程间通信方式一种——管道。

(2)如何进行通信?

在讨论了进程通信的重要性,那么实现它就是很必要的。然而,我们知道,进程具有独立性,那么通信的成本一定不会很低。

  • 管道

  • System V进程间通信

  • POSIX 进程间通信

常见的进程间通信有三种方式。而本节,重要讲管道。

举个例子:
我们在使用QQ或者微信和自己的朋友、家人聊天的时候。发送的消息,一定会满足两个需求,一个是我自己要看到!我发了什么,二个是对方一定要看到,否则就根本无通信的可能。
进程间通信完全可以看作是两个进程 通过某种方式、凭借什么手段,从而让自己发送的信息,能够让对方看到。 我们称这样的一种方式,这样的能被两个进程同时看到的 资源 叫做"临界资源"。

在这种基础上建立的对进程间通信的理解,也就事半功倍。

OS的定位以及重要作用,决定了任何的进程间通信,一定绕不开OS的管理。
OS需要给通信的双方间接维护、建立通信需要的“内存空间”。
并且这种内存空间对于通信双方是 公共可见的

二、匿名管道

(1)什么是管道?

管道是Unix中最古老的进程间通信的形式;
我们把一个进程连接到另外一个进程的数据流,称之为"管道"
它们是一种基于文件系统(同一份资源)的通信方式。

管道分类;

管道分为两类:

  • 匿名管道: 是一种内存级文件

  • 命名管道:是一种磁盘文件,同普通文件一样在磁盘上保存。

如何理解这两种文件呢?那么一定是接下来的重头戏~

(2)创建匿名管道

正如其管道的名字一样,该管道没有"名字"。毕竟是"内存级文件"。

       #include <unistd.h>
       int pipe(int pipefd[2]);
参数pipifd:
    是一个输出型参数,保存的是文件描述符数组。fd[0]表示读端,fd[1]表示写端
return val:
On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

从函数pipe的参数设置就说了,管道支持单向通信的。如果是父进程打开的是写端,那么它自己应该关闭"读端"(即便你不会去读取,但是这保险),而子进程打开的读端,那么顺其自然它应该去关闭自己的"写端"。

(3)管道缓冲区

我们此时让 父进程一直读,子进程每1s中向管道输出一次。

现象是,我们看到每写入一次,就读取一次。

我们对代码进行了修改。

可以看到,当读端一直在管道里读数据的时候,会在由于子进程没有发送数据,那么读端就会在read处陷入阻塞状态。

我们再对代码进行修改;

此时父进程读取的数据,不再是一行一行的了。因为管道的缓冲区,在读取之前,已经有很多数据了。而read的数据大小为 sizeof buffer。

当我们不再进行读取时;

当写入的次数达到一定时,也就不会再进行写入了!因为还有人前来读取数据,释放掉管道的空间!那么管道的空间也是有限的!

(4)读写端关闭

如果父进程正在读取,而此时写端关闭会发什么? 如果子进程正在写入,而父进程读端关闭又会发生什么?

父进程正在读取,而此时写端关闭;

和我们预想的一样,read的返回值当检测到0时,就证明着写端关闭了;

子进程正在写入,而父进程读端关闭;

当读端关闭时,写端也就没有任何意义了。那么此时OS会直接向该进程发送信号(SIGPIPE),终止该进程行为;

(5)读写与匿名管道特征

进行上述那么多的实验,无非就是为了验证下面的总结:

读写特征:
1.读慢,写快。(写端直到把缓冲区打满)
2.读快,写慢。(读端在read处阻塞等待)
3.写关闭,读0结束。
4.读关闭时,写端会被OS发送信号终止。
匿名管道特征:
1.管道的生命周期随进程(内存级文件)
2.一般用来进行具有血缘关系的进程之间(继承文件描述符表)
3.管道是面向字节流
4.半双工 --- 单向通信
5.具有同步与互斥机制

三、命名管道

从名字上就知道,匿名管道和命名管道的区别。是的,管道是基于文件系统的进程间通信方式,匿名管道是内存级文件,因此它不需要有文件名。而,命名管道是实打实的磁盘文件。两个进程建立通信,即共同能够看到一份公共资源,匿名管道是内存级,父子进程通过继承关系,子进程能够看到父进程打开的文件描述符fd。而命名管道,基于磁盘的路径+文件名标识磁盘上唯一的文件,两个进程同时打开这一个文件,也就意味着两个进程能够看到同一份公共资源!

(1)命令行创建管道文件

mkfifo + filename

(2)函数实现创建

       #include <sys/types.h>
       #include <sys/stat.h>
//创建
       int mkfifo(const char *pathname, mode_t mode);
//删除
       #include <unistd.h>
       int unlink(const char *path);

(3)实现一个简单的client\server通信

comm.h:
#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <cassert>

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
#define NAME_PIPE "./named_pipe"

bool CreatePipe(const std::string& path)
{
    umask(0);
    int n = mkfifo(path.c_str(),0666);
    if(n == 0)
    {
        return true;
    }    
    else{
        cout << "create pipe faild" << endl;
        return false;
    }
}


void removeFifo(const std::string& path)
{
    int n = unlink(path.c_str());
}

server:
int main()
{
    // std::cout << "hello server" << std::endl;
    bool r = CreatePipe(NAME_PIPE);
    assert(r);
    (void)r;

    int rfd = open(NAME_PIPE, O_RDONLY);
    if (rfd < 0)
        exit(1);

    char buffer[1024];
    while (true)
    {
        ssize_t s = read(rfd, buffer, sizeof(buffer));
        if (s > 0)
        {
            buffer[s] = 0;
            std::cout << "client->server# " << buffer << std::endl;
        }
        else if (s == 0)
        {
            std::cout << "client quit, me too!" << std::endl;
            break;
        }
        else
        {
            std::cout << "client quit, me too!" << std::endl;
            break;
        }
    }

    close(rfd);
    removeFifo(NAME_PIPE);
    return 0;
}

client:

int main()
{
    // 服务端写数据
    int wfd = open(NAME_PIPE, O_WRONLY);
    if (wfd < 0)
        exit(0);

    char buffer[1024];
    // write;
    while (true)
    {
        fgets(buffer, sizeof(buffer), stdin);
        // 去掉'\n'
        if (strlen(buffer) > 0)
            buffer[strlen(buffer) - 1] = 0;
        ssize_t n = write(wfd, buffer, sizeof(buffer));
        assert(n == strlen(buffer));
        (void)n;
    }

    close(wfd);
    return 0;
}

总结:

①进程间通信的本质在于,让不同进程看到同一份公共资源

②管道是基于文件系统的通信方式。匿名管道属于内存级文件,命名管道属于磁盘的管道文件。

③pipe可以创建匿名管道。多用于具有亲缘关系的进程间通信。

④命名管道可以实现任意两个进程进行通信。mkfifo命令行可以创建管道文件。

本篇到此结束,感谢你的阅读

祝你好运,也向阳而生~

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

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

相关文章

Databend 开源周报第 76 期

英文版移步&#xff1a;https://databend.rs/blog/2023-01-11-databend-weekly Databend 是一款强大的云数仓。专为弹性和高效设计。自由且开源。即刻体验云服务&#xff1a;https://app.databend.com 。 What’s New 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的…

vue 中由浅拷贝引发问题的一些场景

在工作的过程中踩了很多的由浅拷贝导致的坑&#xff0c;今天总结在这里&#xff0c;希望对大家有所帮助 1. 组件中直接抛出一个引用类型变量 &#x1f330;举个例子 &#xff08;ps: 以下代码为伪代码&#xff0c;主要展示逻辑用&#xff09; 子组件&#xff08;uploadImg&a…

线 程 同 步、线程的死锁问题

线程同步&#xff1a; 模拟售票程序出现问题&#xff1a;当多个线程同时访问共享数据时&#xff0c;产生无序、重复、超额售票等多线程安全问题 解决&#xff1a;将多个线程需要访问的共享数据&#xff0c;包装起来视为一个整体&#xff0c;确保一次只有一个线程执行流访问共享…

春节福利丨神策数据 2022 年数字化营销资料打包全送

2022 年&#xff0c;神策数据出品多份行业研究报告&#xff0c;覆盖银行、证券、零售、教育、电商、融合媒体等多个行业&#xff0c;帮助更多企业通过多视角洞见紧握数字化营销的方向和趋势&#xff0c;用方法论结合落地实践驱动企业数字化经营。01B2B 电商数字化运营聚焦四类 …

【自学Python】Python查找字符串位置

Python查找字符串位置 大纲 Python查找字符串位置教程 在开发过程中&#xff0c;很多时候我们有在一个 字符串 中查找另一个字符串位置的需求&#xff0c;在 Python 中&#xff0c;在一个字符串中查找另一个字符串的位置我们使用 index() 函数。 index() 函数的功能与 find(…

力扣(78.90)补9.22

78.子集 感觉不太难&#xff0c;但是就是不会写。感觉回溯里有很多细节问题。 class Solution { private: vector<vector<int>> res; vector<int> num; void back(vector<int>& nums,int index,int end){ res.push_back(num); …

【JavaEE初阶】第三节.多线程基础篇

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 文章目录 前言 一、认识线程 二、多线程程序 2.1 第一个Java多线程程序 2.2 怎么样观察线程的详细情况 2.3 sleep方法 2.4 run 和 start 方法的区别是什么 三、创…

在springboot中配置热部署

今天什么节日也不是&#xff0c;那就祝大家今天快乐。 热部署 所谓热部署&#xff0c;就是在应用正在运行的时候升级软件&#xff0c;却不需要重新启动应用。对于Java应用程序来说&#xff0c;热部署就是在运行时更新Java类文件。在以往&#xff0c;我们对java代码进行修改之后…

【HBU】大一下期末重点

物理简答题一、牛顿第二定律&#xff08;Fdp/dt &#xff09;&#xff1a;1. 飞机怕小鸟:Fdp/dt 力与作用时间的乘积等于物体动量的变化。由于小鸟与飞机相对速度很大&#xff0c;作用时间很短,产生的作用力很大&#xff0c;当小鸟与飞机向撞&#xff0c;效果与同质量炮弹撞飞机…

正则表达式入门及常用正则表达式

常用正则表达式 1 正则表达式的基础概念 1.1 预定义字符 . 表示任何字符&#xff08;与行结束符可能匹配也可能不匹配&#xff09; \d 数字&#xff1a;[0-9] \D 非数字字符&#xff1a;[^0-9] \s 空白字符&#xff1a;[\t\n\xoB\f\r] \S 非空白字符&#xff1a;[^\s] \w 单…

k8s的YAML部署rocketmq记录

说明 测试环境是k8s集群&#xff0c;在上边部署一套单节点的rocketmq nameserver部署 Service和StatefulSet脚本如下 apiVersion: v1 kind: Service metadata:labels:app: rocketmqnamesrvname: rocketmqnamesrv spec:type: ClusterIPports:- port: 9876targetPort: 9876na…

Pytorch深度学习【十四】

批量归一化 归一化 损失出现在最后&#xff0c;后面的层(高级语义层)训练较快数据输入在最底部 底部的层训练慢底部层一变化&#xff0c;所有高级语义层都得跟着变最后的那些层需要重新学习多次—收敛速度变慢 问题—是否可以在学习底部层的时候避免变化顶部层 批量归一化 固定…

8 个精彩的免费 G​​IS 软件资源分享

有人说&#xff1a;一个人从1岁活到80岁很平凡&#xff0c;但如果从80岁倒着活&#xff0c;那么一半以上的人都可能不凡。 生活没有捷径&#xff0c;我们踩过的坑都成为了生活的经验&#xff0c;这些经验越早知道&#xff0c;你要走的弯路就会越少。 GIS 软件有两种通用格式&a…

【面试题】2023年前端最新面试题-性能优化篇

原文见&#xff1a;语雀&#xff08;https://www.yuque.com/deepstates/interview/xtt59x&#xff09; ● 性能指标 ● 分析工具 ● 优化方式 ○ 加载 ○ 渲染 ● 专题优化 ○ 技术栈&#xff1a;react ○ 浏览器 ○ 打包工具&#xff1a;webpack ● 项目 ⭐️⭐️⭐️ 相关知…

如何隐藏电脑硬盘分区?

无论是个人还是公司的电脑我们都会储存一些重要的数据&#xff0c;有些甚至还是涉及个人隐私或公司的商业机密。为了更好地保护电脑磁盘中的重要资料&#xff0c;部分用户希望能将硬盘分区隐藏起来。那么怎么隐藏硬盘分区呢&#xff1f;方法一&#xff1a;使用磁盘管理隐藏硬盘…

将vscode打造为你的开发工具的首选

文章目录前言vscode主要配置vscode的两个主要快捷键Java配置JDK和Gradle环境主要插件常见的配置launch.json配置运行测试用例常见问题Python主要插件settings.json配置Javascript/typescript常用插件settings.json样例Golang参考前言 什么是IDE? IDE 文本编辑 搜索 代码导…

Matlab矩阵和数组的操作

一、矩阵的建立 1、直接输入法 将矩阵的元素用方括号括起来&#xff0c;按矩阵行的顺序输入各元素&#xff0c;同一行的各元素之间用空格或逗号分隔&#xff0c;不同行的元素之间用分号分隔。 A [16 3 2 13; 5 10 11 8; … 9 6 7 12; 4 15 14 1] A 16 3 2 13 5 10 11 8 9 6…

如何有效的增加 shopee 的流量?

很多卖家选择在跨境电商平台开店。说到跨境电商&#xff0c;大家首先想到的应该是亚马逊、易趣等电商平台&#xff0c;边肖会在shopee平台上给大家带来店铺。新店如何获得流量&#xff1f;有哪些方式&#xff1f;米贸搜为你整理如下&#xff1a;shopee店铺如何获取流量&#xf…

Python学习笔记——函数

函数是组织好的&#xff0c;可重复使用的&#xff0c;用来实现单一&#xff0c;或相关联功能的代码段。能提高应用的模块性&#xff0c;和代码的重复利用率。定义函数定义函数使用关键字def&#xff0c;后接函数名&#xff0c;再后接放在圆括号&#xff08;&#xff09;中的可选…

P1036 [NOIP2002 普及组] 选数————C++

题目 [NOIP2002 普及组] 选数 题目描述 已知 nnn 个整数 x1,x2,⋯,xnx_1,x_2,\cdots,x_nx1​,x2​,⋯,xn​&#xff0c;以及 111 个整数 kkk&#xff08;k<nk<nk<n&#xff09;。从 nnn 个整数中任选 kkk 个整数相加&#xff0c;可分别得到一系列的和。例如当 n4n4…