当前位置: 首页 > news >正文

【Linux】进程通信——管道

在这里插入图片描述

欢迎来到Cefler的博客😁
🕌博客主页:折纸花满衣
🏠个人专栏:题目解析
🌎推荐文章:【LeetCode】winter vacation training

在这里插入图片描述


目录

  • 📋进程通信的目的
  • 📋管道
    • 匿名管道
      • pipe函数创建匿名管道
    • 管道的5种特性4种情况
    • 站在文件描述符的角度看管道
    • 命名管道
    • 命名管道和匿名管道的区别
  • 📋命名管道实现两个毫不相干进程间的读写联系
    • Makefile
    • common.h
    • server.cc(读)
    • client.cc(写)

📋进程通信的目的

  • 数据传输:一个进程需要将它的数据发送给另一个进程
  • 资源共享:多个进程之间共享同样的资源。
  • 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
  • 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

📋管道

进程通信的管道底层原理是使用操作系统提供的文件描述符来实现。

在Linux中,管道是通过内核中的缓冲区来实现进程间数据传输的。管道可以被看作是一个字节流,它有两个文件描述符:**一个用于读取数据,一个用于写入数据。**这两个文件描述符分别被称为管道的读端和写端。当一个进程往管道的写端写入数据时,数据会被放入管道的缓冲区中,而另一个进程从管道的读端读取数据时,数据会从缓冲区中被取出。

具体来说,管道的底层原理如下:

  1. 创建管道:当调用pipe()函数时,操作系统会创建一个管道,并返回两个文件描述符,一个用于读取数据,一个用于写入数据。

  2. 数据传输:一个进程可以通过write()系统调用将数据写入管道的写端,数据会被放入管道的缓冲区中。另一个进程可以通过read()系统调用从管道的读端读取数据,数据会从缓冲区中被取出。读写操作是原子的,即每次写入或读取的数据大小是固定的。

  3. 阻塞与非阻塞:管道的写端和读端都可以设置为阻塞或非阻塞模式。在阻塞模式下,如果写端或读端没有准备好(缓冲区已满或为空),相应的写入或读取操作会被阻塞,直到准备好为止

匿名管道

当谈到 Linux 的匿名管道时,我们指的是一种特殊的进程间通信机制。它允许一个进程将输出直接发送给另一个进程,而无需使用临时文件其他形式的中间存储

匿名管道使用竖线符号(|)来表示,通过将一个进程的标准输出连接到另一个进程的标准输入来实现数据传输。这种连接使得第一个进程的输出变为第二个进程的输入,实现了进程间的数据流动。

在 Linux 中,匿名管道是通过 pipe 系统调用创建的。它返回两个文件描述符,一个用于读取数据,另一个用于写入数据。这两个文件描述符可以用于在相关进程之间传输数据。

以下是一个简单的示例来说明匿名管道的使用:

$ ls | grep "txt"

在这个示例中,ls 命令列出当前目录下的所有文件,并将输出通过匿名管道传递给 grep 命令。grep 命令会过滤出包含 “txt” 的文件。

匿名管道对于在 Linux 上进行进程间通信非常有用。然而,它也有一些限制,比如只能实现单向通信,只能用于有亲缘关系的进程(例如父子进程或兄弟进程),并且在数据量较大时可能会引起阻塞。

pipe函数创建匿名管道

pipe 函数是一个系统调用,用于在 Linux 系统中创建一个匿名管道。

它的函数原型如下:

#include <unistd.h>int pipe(int pipefd[2]);

pipe 函数接受一个整型数组 pipefd 作为参数,该数组包含两个文件描述符。pipefd[0] 是管道的读取端,pipefd[1] 是管道的写入端。

当成功调用 pipe 函数时,它会创建一个无名管道,并将对应的文件描述符存储在 pipefd 数组中。这样,我们就可以使用这两个文件描述符来实现进程间的通信。

以下是一个简单的示例,展示了如何使用 pipe 函数创建管道并进行进程间通信:

#include <unistd.h>
#include <stdio.h>
#include <string.h>int main() {int pipefd[2];char buffer[20];// 创建管道if (pipe(pipefd) == -1) {perror("pipe");return 1;}// 创建子进程pid_t pid = fork();if (pid < 0) {perror("fork");return 1;}if (pid == 0) {// 子进程从管道中读取数据close(pipefd[1]);  // 关闭写入端read(pipefd[0], buffer, sizeof(buffer));printf("子进程收到消息:%s\n", buffer);close(pipefd[0]);  // 关闭读取端} else {// 父进程向管道中写入数据close(pipefd[0]);  // 关闭读取端const char* message = "Hello, child!";write(pipefd[1], message, strlen(message) + 1);close(pipefd[1]);  // 关闭写入端}return 0;
}

在这个示例中,父进程创建了一个管道,并通过 write 函数向管道中写入消息。子进程通过 read 函数从管道中读取消息,并输出到控制台。

需要注意的是,为了正确使用管道,我们需要在适当的时候关闭文件描述符。父进程关闭了读取端,子进程关闭了写入端。

以上示例代码可以分为三个步骤
1.建立管道
2.创建子进程
3.父子关闭不需要的fd,形成单向通信的管道

管道的5种特性4种情况

🌈 管道的4种情况
1.如果管道没有数据了,读端就只能等待
2.如果管道被写满了,写端必须等待,直到有空间为止
3.写端关闭,读端一直读取,读端读到read返回值为0,表示读到文件结尾
4.读端关闭,写端一直写入,OS会直接杀掉写端进程,通过向目标进程发送SIGPIPE(13)信号,终止目标进程

🌈 管道的5钟特性
1.只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创
建,然后该进程调用fork,此后父、子进程之间就可应用该管道
2.匿名管道,默认要给读写端提供同步机制
3.匿名管道是面向字节流的(假如写了n量的数据,不一定要全部读入,根据自己的设置需求,想怎么读就怎么读)
4.管道的生命周期是随进程的,进程结束,管道结束
5.管道是单向通信的,半双工通信的一种特殊情况

站在文件描述符的角度看管道

父进程中两个文件描述符分别指向读和写,子进程继承父进程的文件描述符表。
父进程断开写的连接,子进程断开读的连接,最后形成子写,父读
在这里插入图片描述

命名管道

命名管道(Named Pipe),也被称为 FIFO(First In First Out),是一种在 Linux 系统中用于进程间通信的机制。

与匿名管道不同的是,命名管道是通过文件系统中的一个特殊文件来实现的。它具有一个在文件系统中唯一标识的名称,并且可以由多个进程进行读写操作。

要创建一个命名管道,我们可以使用 mkfifo 命令或者在 C 语言中使用 mkfifo 函数。下面是一个示例,演示了如何使用命名管道进行进程间通信:

🍎命令行示例:

首先,在命令行中创建一个命名管道:

$ mkfifo mypipe

然后,在一个终端中执行以下命令,将消息写入命名管道:

$ echo "Hello, named pipe!" > mypipe

最后,在另一个终端中执行以下命令,从命名管道中读取消息:

$ cat mypipe

你将看到第二个终端输出了刚才写入的消息。

🍎C 语言示例:

以下是在 C 语言中使用命名管道进行进程间通信的示例:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>int main() {const char* fifo_file = "mypipe";const char* message = "Hello, named pipe!";char buffer[256];// 创建命名管道mkfifo(fifo_file, 0666);// 打开命名管道进行写操作int fd = open(fifo_file, O_WRONLY);write(fd, message, strlen(message) + 1);close(fd);// 打开命名管道进行读取操作fd = open(fifo_file, O_RDONLY);read(fd, buffer, sizeof(buffer));printf("Received message: %s\n", buffer);close(fd);// 删除命名管道unlink(fifo_file);return 0;
}

在这个示例中,我们首先使用 mkfifo 函数创建了一个命名管道,并指定了文件权限。然后,我们使用 open 函数打开命名管道进行写操作,并通过 write 函数向管道中写入消息。接着,我们再次使用 open 函数打开命名管道进行读取操作,并通过 read 函数读取管道中的消息。

需要注意的是,命名管道是阻塞的如果没有进程同时打开读取端和写入端,那么写入端的进程将会被阻塞,直到有其他进程打开读取端


命名管道和匿名管道的区别

命名管道(Named Pipe)和匿名管道(Anonymous Pipe)是两种不同的进程间通信机制,它们有以下几个区别:

  1. 创建方式:匿名管道通过 pipe 函数创建,而命名管道通过 mkfifo 函数或者命令行的 mkfifo 命令创建。

  2. 文件系统依赖性:匿名管道不依赖于文件系统,它只存在于内存中,没有对应的文件。命名管道则是在文件系统中创建了一个特殊文件,通过该文件进行读写操作。

  3. 进程间关系:匿名管道通常用于父子进程之间的通信,因为它们共享同一个进程空间。而命名管道可以用于任意进程之间的通信,只要它们可以访问到同一个命名管道文件。

  4. 生命周期:匿名管道在创建它的进程结束后自动销毁,无法被其他进程继续使用。而命名管道会一直存在于文件系统中,直到被显式地删除。

  5. 阻塞特性:匿名管道是阻塞的,如果没有进程同时打开读取端和写入端,写入端的进程将会被阻塞。命名管道也是阻塞的,但可以使用非阻塞方式打开以避免阻塞。

  6. 容量限制:匿名管道的容量是有限的,通常是几千字节。命名管道的容量取决于文件系统,一般比匿名管道大得多。

📋命名管道实现两个毫不相干进程间的读写联系

Makefile

.PHONY:all
all:server client #依赖关系,生成全部client:client.ccg++ -o $@ $^ -std=c++11
server:server.ccg++ -o $@ $^ -std=c++11
.PHONY:clean
clean:rm -f server client .fifo

common.h

#pragma once#define FILENAME ".fifo"

server.cc(读)

#include<iostream>
#include<cstring>
#include<cerrno>
#include <sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>#include "common.h"
using namespace std;int main()
{int n = mkfifo(FILENAME,0666);//创建命名管道if(n<0){cerr<<"errno:"<<errno<<",errstring:"<<strerror(errno)<<endl;return 1;}cout<<"mkfifo success...read"<<endl;int rfd = open(FILENAME,O_RDONLY);if(rfd<0){cerr<<"errno:"<<errno<<",errstring:"<<strerror(errno)<<endl;return 2;}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;}else if(s==0){cout<<"client quit,server quit too"<<endl;break;}}close(rfd);cout<<"close fifo success..."<<endl;return 0;
}

client.cc(写)

#include<iostream>
#include<cstring>
#include<cerrno>
#include <sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>#include "common.h"
using namespace std;int main()
{int wfd = open(FILENAME,O_WRONLY);if(wfd<0){cerr<<"errno:"<<errno<<",errstring:"<<strerror(errno)<<endl;return 1;}cout<<"open fifo success...write"<<endl;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;break;}}close(wfd);return 0;
}

在这里插入图片描述

相关文章:

【Linux】进程通信——管道

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 &#x1f3e0;个人专栏&#xff1a;题目解析 &#x1f30e;推荐文章&#xff1a;【LeetCode】winter vacation training 目录 &#x1f4cb;进程通信的目的&#x1f4cb;管道匿名管道pipe函数创…...

3d gaussian splatting笔记(paper部分翻译)

本文为3DGS paper的部分翻译。 基于点的&#x1d6fc;混合和 NeRF 风格的体积渲染本质上共享相同的图像形成模型。 具体来说&#xff0c;颜色 &#x1d436; 由沿射线的体积渲染给出&#xff1a; 其中密度 &#x1d70e;、透射率 &#x1d447; 和颜色 c 的样本是沿着射线以…...

TCP 三次握手以及滑动窗口

TCP 三次握手 简介&#xff1a; TCP 是一种面向连接的单播协议&#xff0c;在发送数据前&#xff0c;通信双方必须在彼此间建立一条连接。所谓的 “ 连接” &#xff0c;其实是客户端和服务器的内存里保存的一份关于对方的信息&#xff0c;如 IP 地址、端口号等。 TCP 可以…...

Vue3 Cli5按需导入ElementPlus

1、安装环境 node&#xff1a;16.20.0 vue&#xff1a;3.2.36 vue/cli&#xff1a;5.0.0 element-plus&#xff1a;2.2.25 element-plus/icons-vue&#xff1a;2.0.10 unplugin-auto-import&#xff1a;0.16.1 // 当前环境用这个包&#xff0c;不然会提示各种错误 unplugin-vu…...

playwright自动化项目搭建

具备功能 关键技术&#xff1a; pylaywright测试库pytest单元测试框架pytest-playwright插件 非关键技术&#xff1a; pytest-html插件pytest-rerunfailures插件seldom 测试框架 实现功能&#xff1a; 元素定位与操作分离失败自动截图并保存到HTML报告失败重跑可配置不同…...

mysql字符集

一、查看字符集 //查看数据库字符集 SHOW CREATE DATABASE databasename; //查看表字符集 SHOW CREATE TABLE tablename; //查看指定表全部字段字符集 show full columns from table; 二、修改字符集 将超出utf8字符集范围的字符比如&#x2aa27;插入到utf8字符集的字…...

Elasticsearch:聊天机器人、人工智能和人力资源:电信公司和企业组织的成功组合

作者&#xff1a;来自 Elastic Jrgen Obermann, Piotr Kobziakowski 让我们来谈谈大型企业人力资源领域中一些很酷且改变游戏规则的东西&#xff1a;生成式 AI 和 Elastic Stack 的绝佳组合。 现在&#xff0c;想象一下大型电信公司的典型人力资源部门 — 他们正在处理一百万件…...

[AIGC大数据基础] Flink: 大数据流处理的未来

Flink 是一个分布式流处理引擎&#xff0c;它被广泛应用于大数据领域&#xff0c;具有高效、可扩展和容错的特性。它是由 Apache 软件基金会开发和维护的开源项目&#xff0c;并且在业界中受到了广泛认可和使用。 文章目录 什么是 FlinkFlink 的特点真正的流处理高性能和低延迟…...

数据结构之线性表(一般的线性表)

前言 接下来就开始正式进入数据结构环节了&#xff0c;我们先从线性表开始。 线性表 线性表&#xff08;linear list&#xff09;也叫线性存储结构&#xff0c;即数据元素的逻辑结构为线性的数据表&#xff0c;它是数据结构中最简单和最常用的一种存储结构&#xff0c;专门存…...

uniapp安卓android离线打包本地打包整理

离线打包准备 下载Android studio 1.准备资源hbuilder 2.准备离线SDK 最新android平台SDK下载最新android平台SDK下载 3.离线打包key申请 4.直接导入HBuilder-Integrate-AS工程,直接运行simpleDemo项目即可 5.安装java 1.8 jdk-8u151-windows-x64 6.遇到这个报错报错Caus…...

vmware安装centos8-stream

VMware与CentOS8-stream的配置教程【2022-9-5】_centos stream 8-CSDN博客 启动进入后配置网络&#xff0c;/etc/sysconfig/network-scripts/网卡 vmware上的centos8没有网络_主机时wifi上网,centos 8 安装后无法连接网络 解决办法-CSDN博客 centos8配置网络_centos8网络配置…...

使用HttpServletRequestWrapper解决web项目request数据流无法重复读取的问题

在做web项目开发时&#xff0c;我们有时候需要做一些前置的拦截判断处理&#xff0c;比如非法参数校验&#xff0c;防攻击拦截&#xff0c;统一日志处理等&#xff0c;而请求参数如果是form表单提交还好处理&#xff1b;对于json这种输入流的数据就会有问题&#xff0c;统一处理…...

从CNN ,LSTM 到Transformer的综述

前情提要&#xff1a;文本大量参照了以下的博客&#xff0c;本文创作的初衷是为了分享博主自己的学习和理解。对于刚开始接触NLP的同学来说&#xff0c;可以结合唐宇迪老师的B站视频【【NLP精华版教程】强推&#xff01;不愧是的最完整的NLP教程和学习路线图从原理构成开始学&a…...

Git学习笔记:1 基础命令详解

文章目录 Git基础命令详解&#xff1a; Git基础命令详解&#xff1a; git commit 用法&#xff1a;git commit -m "commit message"功能&#xff1a;将暂存区&#xff08;stage&#xff09;中的所有更改提交到本地仓库的当前分支&#xff0c;同时提供一个简短的提交信…...

【服务器】安装宝塔面板

目录 &#x1f33a;【前言】 &#x1f33c;【前提】连接服务器 &#x1f337;方式一 使用工具登录服务器如Xshell &#x1f337;方式二 阿里云直接连接 &#x1f33c; 1. 安装宝塔 &#x1f337;获取安装脚本 方式一 使用下面提供的脚本安装 方式二 使用官网提供的脚本…...

开源模型应用落地-业务优化篇(一)

一、前言 通过参与“开源模型应用落地-业务整合系列篇”的学习,我们已经成功建立了基本的业务流程。然而,这只是迈出了万里长征的第一步。现在我们要对整个项目进行优化,以提高效率。我们计划利用线程池来加快处理速度,使用redis来实现排队需求,以及通过多级环境来减轻负载…...

【遥感专题系列】影像信息提取之——基于专家知识的决策树分类

可以将多源数据用于影像分类当中&#xff0c;这就是专家知识的决策树分类器&#xff0c;本专题以ENVI中Decision Tree为例来叙述这一分类器。 本专题包括以下内容&#xff1a; 专家知识分类器概述知识&#xff08;规则&#xff09;定义ENVI中Decision Tree的使用 概述 基于知…...

lqb日志08

一只小蒟蒻备考蓝桥杯的日志 文章目录 笔记坐标相遇判断工作调度问题&#xff08;抽象时间轴绘制&#xff09; 刷题心得小结 笔记 坐标相遇判断 我是小懒虫&#xff0c;碰了一下运气&#xff0c;开了个“恰当”的数&#xff08;7000&#xff09;如果&#xff0c;7000次还不能…...

SAP EXCEL上传如何实现指定读取某一个sheet页(ALSM_EXCEL_TO_INTERNAL_TABLE)

如何读取指定的EXCEL sheet 页签&#xff0c;比如要读取下图中第二个输出sheet页签 具体实现方法如下&#xff1a; 拷贝标准的函数ALSM_EXCEL_TO_INTERNAL_TABLE封装成一个自定义函数ZCALSM_EXCEL_TO_INTERNAL_TABLE 在自定义函数导入参数页签新增一个参数SHEET_NAME 在源代码…...

奇怪问题说 - 测试篇

文章目录 1.什么是软件测试2.软件测试和开发的区别3.软件测试的发展&#xff1a;4.软件测试岗位5.软件测试在不同类型公司的定位6.一个优秀的软件测试人员具备的素质6.1综合能力6.2掌握自动化测试技术6.3优秀的测试用例设计能力6.4探索性思维6.5有责任感和一定的压力 7.软件测试…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

云原生周刊:k0s 成为 CNCF 沙箱项目

开源项目推荐 HAMi HAMi&#xff08;原名 k8s‑vGPU‑scheduler&#xff09;是一款 CNCF Sandbox 级别的开源 K8s 中间件&#xff0c;通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度&#xff0c;为容器提供统一接口&#xff0c;实现细粒度资源配额…...