【Linux】进程间通信方式之管道

🤖个人主页:晚风相伴-CSDN博客

💖如果觉得内容对你有帮助的话,还请给博主一键三连(点赞💜、收藏🧡、关注💚)吧

🙏如果内容有误的话,还望指出,谢谢!!!

✨下一篇文章:《进程间通信之共享内存》敬请期待💪

目录

理解进程间通信的本质

管道

管道的分类

匿名管道 

匿名管道如何实现进程间通信

 从文件描述符的角度理解匿名管道

用代码实现匿名管道

匿名管道读写的4个特殊情况 

管道的特点

利用匿名管道设计一个进程池

命名管道 

命名管道如何实现进程间通信 

命名管道的创建

代码实现命名管道 


理解进程间通信的本质

因为进程具有独立性,所以每个进程都只知道自己,而不知道有另外的进程存在,所以要实现不同进程间的通信,就要让不同的进程都能看到同一块资源,这块资源不属于任意一个进程,而是强调共享,利用这块资源就可以实现进程间通信了。

总结一下要点 

  1. 进程间通信的前提是要让不同的进程看到同一块资源
  2. 这一块资源不隶属于任何一个进程,而是被这些进程所共享

管道

管道想必大家都不陌生吧,在Linux命令行中我们可以通过管道( | )将一个进程输出连接到另一个进程的输入,从而实现数据的传输、连接、过滤和处理等功能。例如

管道也好理解就比如家里面的水管,一端进水,另一端出水。

管道的分类

  • 匿名管道
  • 命名管道 

🔥匿名管道 

匿名管道主要用于父子进程之间的通信。 

创建匿名管道的接口

 

参数:fildes是一个文件描述符数组,fildes[0]表示读端,fildes[1]表示写端

返回值:成功返回0,失败则返回-1并设置对应的错误码

🔥匿名管道如何实现进程间通信

  1. 父进程创建匿名管道,得到两个文件描述符,一个文件描述符用来读数据,另一个文件描述符用来写数据
  2. 调用fork创建子进程,创建出来的子进程会继承父进程创建管道时获得的那两个文件描述符
  3. 在父子进程中关闭不需要的文件描述符,比如子进程读取数据,父进程写入数据,那就在子进程中关闭写入的文件描述符,父进程中关闭读取的文件描述符,之后就可以进行相应的通信操作了。

 🔥从文件描述符的角度理解匿名管道

用代码实现匿名管道

#include <iostream>
#include <cstdio>
#include <cstring>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>using namespace std;int main()
{//1.创建管道int pipefd[2] = {0};//pipefd[0]:读端,pipefd[1]:写端int n = pipe(pipefd);assert(n != -1);//在Debug下才有用(void)n;//确保在release不报警告//条件编译
#ifdef DEBUGcout << "pipefd[0]:" << pipefd[0] << endl;cout << "pipefd[1]:" << pipefd[1] << endl;
#endif//2.创建子进程并构建通信信道——父进程写入,子进程读取pid_t id = fork();assert(id != -1);if(id == 0){//子进程close(pipefd[1]);//关闭子进程不需要的fd//读取数据char buffer[1024];while(true){//sleep(10);ssize_t s = read(pipefd[0], buffer, sizeof buffer - 1);if(s > 0){buffer[s] = 0;cout << "child get a massage [" << getpid() << "] father say:" << buffer << endl;}}close(pipefd[0]);exit(0);}//父进程close(pipefd[0]);//关闭父进程不需要的fd//发送数据string message = "我是父进程,我正在给你发送数据";int count = 0;//统计发送次数char send_buffer[1024];while(true){//sleep(10);//将要发送的数据打入send_massage中snprintf(send_buffer, sizeof send_buffer, "%s[%d] : %d\n", message.c_str(), getpid(), count++);//写入数据write(pipefd[1], send_buffer, strlen(send_buffer));sleep(1);}//等待子进程退出pid_t ret = waitpid(id, nullptr, 0);assert(ret);(void)ret;close(pipefd[1]);return 0;
}

 运行结果

🔥匿名管道读写的4个特殊情况 

情况一:写端很快,读端很慢,写端将缓冲区写满后就不能再写了,必须等读端读取后才能写让子进程读端sleep(10)秒钟

情况二:写端很慢,读端很快,管道中没有数据的时候,读端必须等待写端写入数据之后才能读

让父进程写端sleep(10)秒钟

情况三:写端关闭,读端读到0时表示读到了文件末尾

现象就是它会阻塞在那

情况四:读端关闭,写端继续写,当将缓冲区写满后操作系统会终止写进程

🔥管道的特点

  1. 管道是用于具有亲缘关系的进程之间进行进程间通信(常用于父子进程)
  2. 管道可以让父子进程之间进行协同,并且提供了访问控制(上面的4种情况就是访问控制的体现)
  3. 管道提供的是面向流式的通信服务(面向字节流)
  4. 管道的生命周期是随进程的
  5. 管道是单向通信的,也就是半双工通信的一种特殊情况

完整代码链接:匿名管道

利用匿名管道设计一个进程池

原理:fork多个子进程,然后用个随机数式的负载均衡让多个子进程都有概率能被使用到

 

匿名管道版进程池完整代码链接:匿名管道版进程池

🔥命名管道 

匿名管道的一个限制就是只能在具有亲缘关系的进程间通信,但是如果我们想在不相关的进程之间实现通信,那么就需要用到命名管道。

🔥命名管道如何实现进程间通信 

要实现进程间通信本质是要让不同的进程看到同一块资源。命名管道其实是在磁盘上创建了一个管道文件,这个管道文件可以随意被命名,并且有对应的属性但是没有内容,当我们在一个进程中打开这个管道文件并且将数据写入这个文件中,另一个进程也就可以打开这个管道文件并且从这个文件中读取数据,不同的进程都能打开并使用这个管道文件,所以也就让不同的进程看到了同一块资源。并且在这读写过程中管道文件中的数据不会加载到磁盘中,所以管道文件的大小始终为0保持不变。

命名管道的创建

在命令行上可以使用mkfifo命令来创建一个命名管道

也可以使用系统接口来创建命名管道

参数

  • pathname:命名管道文件的路径     
  • mode:管道文件的权限

返回值:成功返回0,失败则返回-1

代码实现命名管道 

comm.hpp 

#ifndef _COMM_H_
#define _COMM_H_#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "log.hpp"using namespace std;#define MODE 0666 // 文件权限
#define SIZE 128string ipcPath = "./myfifo.ipc"; // 管道文件路径#endif

server.cc

#include "comm.hpp"
#include <sys/wait.h>static void getMessage(int fd)
{// 进行通信操作char buffer[SIZE];while (true){memset(buffer, '\0', sizeof buffer);ssize_t s = read(fd, buffer, sizeof(buffer) - 1);if (s > 0){// 读取成功cout << "[" << getpid() << "] "<< "client say> " << buffer << endl;}else if (s == 0){// 读到文件结尾cerr << "[" << getpid() << "] "<< "read end of file, client quit, server quit too!" << endl;break;}else{// 读取失败perror("read");break;}}
}int main()
{// 创建管道文件if (mkfifo(ipcPath.c_str(), MODE) < 0){perror("mkfifo");exit(1);}logMessage(NORMAL, "创建管道文件成功, step 1"); // 打印日志// 打开管道文件int fd = open(ipcPath.c_str(), O_RDONLY);if (fd < 0){perror("open");exit(2);}logMessage(NORMAL, "打开管道文件成功, step 2");int nums = 5;for (int i = 0; i < nums; i++){pid_t id = fork();if (id == 0){// 子进程抢占式读取消息getMessage(fd);exit(1);}}// 等待子进程退出for (int i = 0; i < nums; i++){waitpid(-1, nullptr, 0);}// 关闭文件close(fd);logMessage(NORMAL, "关闭管道文件成功, step 3");// 通信完成,将管道文件删除unlink(ipcPath.c_str());logMessage(NORMAL, "删除管道文件成功, step 4");return 0;
}

client.cc 

#include "comm.hpp"int main()
{//获取管道文件int fd = open(ipcPath.c_str(), O_WRONLY);if(fd < 0){perror("open");exit(1);}//发送消息string buffer;while(true){cout << "Please Enter Message Line > ";getline(cin, buffer);write(fd, buffer.c_str(), buffer.size());}//关闭文件描述符close(fd);return 0;
}

完整代码链接:命名管道

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

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

相关文章

7.基于麻雀搜索算法(SSA)优化VMD参数(SSA-VMD)

01.智能优化算法优化VMD参数的使用说明 02.基本原理 麻雀搜索算法&#xff08;SSA&#xff09;是一种基于鸟类觅食行为的启发式优化算法&#xff0c;它模拟了麻雀在觅食时的群体行为&#xff0c;通过模拟麻雀的觅食过程来寻找问题的最优解。SSA的基本原理是通过模拟麻雀的搜索…

机器学习初学者 6 个核心算法!建议收藏,反复观看!

今天再来介绍机器学习算法的基本概念和适用场景&#xff01; 首先&#xff0c;引用一句英国统计学家George E. P. Box的名言&#xff1a;All models are wrong, but some are useful. 没有哪一种算法能够适用所有情况&#xff0c;只有针对某一种问题更有用的算法。 也就是说&…

Linux-笔记 修改开发板默认时区

1. 时区文件 使用命令date -R查看当前的默认时区&#xff0c;date - R命令会自动解析/etc/localtime 文件&#xff0c;而该文件又是指向“ /usr/share/zoneinfo/$主时区/$次时区 ”&#xff0c;当需要更改到指定的时区只要将/etc/localtime 文件软链接到 ”/usr/share/zoneinf…

视频降噪算法 hqdn3d 原理分析

视频降噪 视频降噪是一种处理技术&#xff0c;旨在减少视频中的噪声&#xff0c;提高画面质量。噪声可能来自多种源头&#xff0c;包括摄像机的传感器、压缩算法、传输过程中的干扰等。降噪处理对于视频监控、视频会议、电影后期制作以及任何需要高画质输出的应用场景都非常重…

Linux进程——Linux环境变量

前言&#xff1a;在结束完上一篇的命令行参数时&#xff0c;我们简单的了解了一下Linux中的环境变量PATH&#xff0c;而环境变量不只有PATH&#xff0c;关于更多环境变量的知识我们将在本篇展开&#xff01; 本篇主要内容&#xff1a; 常见的环境变量 获取环境变量的三种方式 本…

springcloud服务间调用 feign 的使用

引入依赖包 <!-- 服务调用feign --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>创建调用外部服务的接口 需要使用的地方注入 使用 启动类增…

【ai早报-01 project】

今天和大家分享一款有趣的开源项目 01 Project。 The 01 Project is building an open-source ecosystem for AI devices. 其主旨是基于开源生态&#xff0c;构建以LLM为核心的产品&#xff0c;提供软硬件方案。 市面上类似产品: Rabbit R1, Humane Pin。 如上图所示的这款产…

解决方案:‘Series‘ object has no attribute ‘xxxx‘

文章目录 一、现象二、解决方案 一、现象 ...... model.fit(X_train, y_train) y_pred model.predict(X_test) recall recall_score(y_test, y_pred) precision precision_score(y_test. y_pred) ......执行语句到**“precision precision_score(y_test. y_pred)”**这里发…

通用型产品发布解决方案(基础环境搭建)

文章目录 1.项目技术栈和前置技术2.创建Linux平台1.需求分析2.安装Virtual Box1.BIOS里修改设置开启虚拟化设备支持&#xff08;f2 或f10&#xff09;2.任务管理器 -> cpu 查看虚拟化是否开启3.卸载方式4.安装6.1.265.管理员身份运行&#xff0c;选择安装位置6.一直下一步&a…

鸿蒙开发接口Ability框架:【(StaticSubscriberExtensionAbility)】

StaticSubscriberExtensionAbility StaticSubscriberExtensionAbility模块提供静态订阅者扩展能力的类别的能力。 说明&#xff1a; 本模块首批接口从API version 9 开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 本模块接口仅可在Stage模型下…

AI讲师大模型培训老师叶梓:大模型应用的方向探讨

大模型应用的关键方向及其落地案例可以从多个角度进行探讨&#xff0c;结合最新的研究和实际应用案例&#xff0c;我们可以更全面地理解这些技术如何推动社会和经济的发展。 Agent&#xff08;数字代理&#xff09;: 方向说明:Agent方向的AI技术旨在创建能够独立执行任务、做出…

JavaWeb_请求响应_简单参数实体参数

一、SpringBoot方式接收携带简单参数的请求 简单参数&#xff1a;参数名与形参变量名相同&#xff0c;定义形参即可接收参数。并且在接收过程中&#xff0c;会进行自动的类型转换。 启动应用程序后&#xff0c;在postman中进行测试&#xff1a; 请求成功&#xff0c;响应回了O…