当前位置: 首页 > 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.软件测试…...

中国新能源汽车持续跑出发展“加速度”,比亚迪迎来向上突破

2023年已经过去&#xff0c;对于汽车圈而言&#xff0c;2023年是中国车市的分水岭&#xff0c;在这一年&#xff0c;中国汽车工业70年以来首次进入全球序列&#xff0c;自主品牌强势霸榜&#xff0c;销量首次超过合资车。要知道&#xff0c;这是自大众于1984年进入中国市场成立…...

chatGPT辅助写硕士毕业论文

一、写作顺序 1.标题、研究问题、研究方法 2.文献综述&#xff08;占比1/5-1/6&#xff09; 3.论证章节 4.结论、不足、启示 5.处理图表、参考文献的格式 6.绪论或引言 7.摘要、关键词 8.查重、装订 http://【硕士毕业论文写不下去&#xff0c;多亏听了张博士的论文写…...

搭建nginx图片服务器

&#xff08;1&#xff09;将图片存储于/home/data/images目录&#xff1b; &#xff08;2&#xff09;配置nginx.conf user nginx; worker_processes 4;error_log /var/log/nginx/error.log notice; pid /var/run/nginx.pid;events {worker_connections 10000; }ht…...

大数据学习之Flink算子、了解DataStream API(基础篇一)

DataStream API &#xff08;基础篇&#xff09; 注&#xff1a; 本文只涉及DataStream 原因&#xff1a;随着大数据和流式计算需求的增长&#xff0c;处理实时数据流变得越来越重要。因此&#xff0c;DataStream由于其处理实时数据流的特性和能力&#xff0c;逐渐替代了DataSe…...

js中字符串string,遍历json/Object【匹配url、邮箱、电话,版本号,千位分割,判断回文】

目录 正则 合法的URL 邮箱、电话 字符串方法 千位分割&#xff1a;num.slice(render, len).match(/\d{3}/g).join(,) 版本号比较 判断回文 json/Object 遍历 自身属性 for...inhasOwnProperty(key) Object.获取数组(obj)&#xff1a;Object.keys&#xff0c;Object…...

字符串和C预处理器

本文参考C Primer Plus第四章学习 文章目录 常量和预处理器const限定符 1. 常量和预处理器 有时&#xff0c;在程序中要使用常量。例如&#xff0c;可以这样计算圆的周长&#xff1a; circumference 3.14159 * diameter; 这里&#xff0c;常量3.14159 代表著名的常量 pi(π)。…...

Ultraleap 3Di新建项目之给所有的Joint挂载物体

工程文件 Ultraleap 3Di给所有的Joint挂载物体 前期准备 参考上一期文章&#xff0c;进行正确配置 Ultraleap 3Di配置以及在 Unity 中使用 Ultraleap 3Di手部跟踪 新建项目 初始项目如下&#xff1a; 新建Create Empty 将新建的Create Empty&#xff0c;重命名为LeapPro…...

关于session每次请求都会改变的问题

这几天在部署一个前后端分离的项目&#xff0c;使用docker进行部署&#xff0c;在本地测试没有一点问题没有&#xff0c;前脚刚把后端部署到服务器&#xff0c;后脚测试就出现了问题&#xff01;查看控制台报错提示跨域错误&#xff1f;但是对于静态资源请求&#xff0c;包括登…...

【leetcode题解C++】150.逆波兰表达式求值 and 239.滑动窗口最大值 and 347.前k个高频元素

150.逆波兰表达式求值 给你一个字符串数组 tokens &#xff0c;表示一个根据 逆波兰表示法 表示的算术表达式。 请你计算该表达式。返回一个表示表达式值的整数。 注意&#xff1a; 有效的算符为 、-、* 和 / 。每个操作数&#xff08;运算对象&#xff09;都可以是一个整数…...

【计网·湖科大·思科】实验三 总线型以太网的特性、集线器和交换机的区别、交换机的自学习算法

&#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&#xff0c;你的&#x1f44d;点赞&#x1f64c;收藏❤️关注对我真的很重要&…...