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

【linux深入剖析】进程间通信


🍁你好,我是 RO-BERRY
📗 致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识
🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油

在这里插入图片描述


目录

  • 1.进程间通信目的
  • 2. 什么是进程间通信
  • 3. 进程间通信发展
  • 4.如何进行进程间通信
    • 4.1 一般规律
    • 4.2 具体做法
  • 5.进程间通信分类
  • 6. 管道
    • 匿名管道
    • 用fork来共享管道原理
    • 站在文件描述符角度-深度理解管道
    • 验证管道通信代码


1.进程间通信目的

两个进程之间,可以进行“数据”的直接传递吗?不能!进程具有独立性

那么为什么需要进程间通信呢?

  • 数据传输:一个进程需要将它的数据发送给另一个进程

在很多场景之间,两个进程需要进行数据传输,比如:A进程负责获取网络中的数据,但是它并不会去处理这份数据,而B进程为只负责处理数据,这样就可以实现多进程的并发

  • 资源共享:多个进程之间共享同样的资源。

有一部分进程需要进行共享一份资源,以便于两进程共同访问共同完成一件事情,比如说:我们玩游戏,多玩家在同一局游戏中,我们看到的数据都是一模一样的,我们的每个用户也就是一个进程,我们对于地图资源进行的是共享

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

2. 什么是进程间通信

  • 进程间通信(Inter-process Communication,IPC)是指在多道程序环境下,进程间进行数据交换和信息传递的一种机制或方法。在现代操作系统中,进程是系统资源分配的基本单位,不同进程之间需要相互合作和通信,才能完成各种任务。进程间通信是实现进程间协作的重要手段。

  • 常用的进程间通信方式有管道、消息队列、共享内存、信号量和套接字等。管道是一种半双工的通信方式,消息队列是一种异步通信方式,共享内存是一种高效的通信方式,信号量是一种用于同步进程的通信方式,套接字是一种网络通信方式。


3. 进程间通信发展

进程间通信是指不同进程之间的数据交换和共享,是操作系统中非常重要的一个概念。随着计算机技术的发展,进程间通信也经历了多个发展阶段。

  • 第一阶段是管道,它是Unix系统中最早的进程间通信方式,可以在两个相关进程之间传递数据。

  • 第二阶段是信号,它是Unix系统中另一种进程间通信方式,用于通知接收进程某个事件已经发生。

  • 第三阶段是共享内存,它可以允许多个进程访问同一块物理内存,从而实现数据共享。

  • 第四阶段是消息队列,它可以在不同进程之间传递消息,实现进程间通信。

  • 第五阶段是套接字,它可以在不同主机之间传递数据,并且支持多种通信协议。

  • 第六阶段是远程过程调用(RPC),它允许程序员在不同计算机上运行的程序之间进行交互。


4.如何进行进程间通信

4.1 一般规律

  • 进程间通信的本质:让不同的进程,看到同一份资源(一般都是由OS提供)

进程间通信需要一个另外的交换数据的空间(内存)

此交换空间不能由通信双方任何一方进行提供,如果提供了空间,让对方进程来进行访问,这就有违背进程独立性,所以我们需要另一个额外空间进行数据的传输,这种事情会有OS来进行操作


4.2 具体做法

OS提供的“空间”有不同的样式,这决定了不同的通信方式

常见通信方式:

  1. 管道(匿名和命名)
  2. 共享内存
  3. 消息队列
  4. 信号量

5.进程间通信分类

🍁管道

  • 匿名管道pipe
  • 命名管道

🍁System V IPC

System V IPC是指System V操作系统提供的进程间通信(IPC)机制,它允许进程在不同的计算机系统之间进行通信和同步。System V IPC主要包括三种类型的通信机制:消息队列、共享内存和信号量。

  • System V 消息队列
  • System V 共享内存
  • System V 信号量

🍁POSIX IPC

POSIX IPC 是指可移植操作系统接口(Portable Operating System Interface,缩写为POSIX)中的进程间通信(Inter-Process Communication,缩写为IPC)机制。它提供了一组标准的函数和数据结构,用于在不同的进程间进行数据交换和同步操作。常用的 POSIX IPC 包括消息队列、共享内存、信号量等。使用 POSIX IPC 可以实现不同进程之间的数据共享和通信,进而实现更加复杂的多进程协作模式。

  • 消息队列
  • 共享内存
  • 信号量
  • 互斥量
  • 条件变量
  • 读写锁

6. 管道

  • 管道是Unix中最古老的进程间通信的形式。
  • 我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”

管道是一种进程间通信机制,它可以用来在不同进程间传递数据。在底层实现上,管道其实是一种内核缓冲区,它由两个文件描述符(文件句柄)表示,一个用于读取,一个用于写入。当一个进程向管道中写入数据时,数据会被存储到内核缓冲区中,另一个进程则可以从同一个管道中读取这些数据。

管道底层实现的关键是通过操作系统提供的内核缓冲区实现进程间的数据传输。管道有两个缓冲区,分别用于存储读取和写入的数据。当写入进程向管道中写入数据时,数据会被存储到写入缓冲区中。如果写入缓冲区已满,则写入进程会被阻塞,直到有足够的空间来存储数据。当读取进程从管道中读取数据时,数据会从读取缓冲区中读取。如果读取缓冲区为空,则读取进程也会被阻塞,直到有新的数据可供读取。

需要注意的是,管道具有单向性,即数据只能从一个方向流动。如果需要双向通信,则需要创建两个管道。同时,在管道中传递的数据是没有结构的字节流,因此需要约定好传递的数据格式以及数据长度。

匿名管道

#include <unistd.h>
功能:创建一无名管道
原型
int pipe(int fd[2]);
参数
fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端
返回值:成功返回0,失败返回错误代码

这个函数让我们不需要向磁盘中刷新并且磁盘中并不存在文件,其本质就是会创建一个内存级的文件,这个文件没有名字,为匿名文件(管道)

匿名管道如何做到让不同的进程看到同一份资源?

就是利用了创建子进程,子进程会创建父进程的相关属性信息,匿名管道可以(只能)进行具有血缘关系的进程,进行进程间通信,常用于父子

在这里插入图片描述
实例代码

例子:从键盘读取数据,写入管道,读取管道,写到屏幕
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(void)
{int fds[2];char buf[100];int len;if (pipe(fds) == -1)perror("make pipe"), exit(1);// read from stdinwhile (fgets(buf, 100, stdin)) {len = strlen(buf);// write into pipeif (write(fds[1], buf, len) != len) {perror("write to pipe");break;}memset(buf, 0x00, sizeof(buf));// read from pipeif ((len = read(fds[0], buf, 100)) == -1) {perror("read from pipe");break;}// write to stdoutif (write(1, buf, len) != len) {perror("write to stdout");break;}}
}

用fork来共享管道原理

在这里插入图片描述

站在文件描述符角度-深度理解管道

在这里插入图片描述

为什么父进程最开始就要按照r和w打开同一个文件呢?
这是因为管道只允许一个人读,一个人写。

验证管道通信代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>void writer(int wfd)
{const char *str ="hello father, I am child";char buffer[128];int cnt = 0;pid_t pid  = getpid();while(1){snprintf(buffer, sizeof(buffer),"message: %s,pid: %d,count: %d \n", str, pid, cnt);write(wfd,buffer,strlen(buffer)+1);cnt++;sleep(1);}
}
void reader(int rfd)
{char buffer[1024];while(1){ssize_t n = read(rfd, buffer, sizeof(buffer)-1);(void)n;   //读取但是没有用printf("father get a message: %s", buffer);}
}int main()
{int pipefd[2];int n = pipe(pipefd);if(n<0) return 1;printf("pipefd[0]: %d, pipefd[1]: %d\n", pipefd[0]/*read*/, pipefd[1])/*write*/; //创建管道//父子进程pid_t id=fork();if(id == 0){//child 实现W 关闭读取保留写入close(pipefd[0]);writer(pipefd[1]);exit(0);}//father实现rclose(pipefd[1]);reader(pipefd[0]);wait(NULL);return 0;
}

在这里插入图片描述
这里可以在左边看到有两个进程同时运行,初步实现管道通信,子进程可以写给父程序

相关文章:

  • Spark 核心编程之 RDD 介绍
  • 独家首发 | 基于 KAN、KAN卷积的轴承故障诊断模型
  • 【SpringMVC】_简单示例计算器
  • PMP认证与NPDP认证哪个含金量高?
  • Redis 和 Mysql 如何保证两者数据一致性
  • Android下HWC以及drm_hwcomposer普法(下)
  • 2024盘古石初赛(服务器部分)
  • 前后端联调小细节
  • Go 如何通过 Kafka 客户端库 生产与消费消息
  • 2023年西安交通大学校赛(E-雪中楼)
  • 【深度学习】YOLOv10实战:20行代码将笔记本摄像头改装成目标检测监控
  • 实现样式一键切换
  • 超融合架构下,虚拟机高可用机制如何构建?
  • android 应用安装目录
  • 跨境电商多店铺:怎么管理?风险如何规避?
  • [NodeJS] 关于Buffer
  • Apache Zeppelin在Apache Trafodion上的可视化
  • git 常用命令
  • Octave 入门
  • RxJS: 简单入门
  • supervisor 永不挂掉的进程 安装以及使用
  • vuex 学习笔记 01
  • 案例分享〡三拾众筹持续交付开发流程支撑创新业务
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 判断客户端类型,Android,iOS,PC
  • 如何使用 JavaScript 解析 URL
  • 实现菜单下拉伸展折叠效果demo
  • 线上 python http server profile 实践
  • 如何在 Intellij IDEA 更高效地将应用部署到容器服务 Kubernetes ...
  • ​猴子吃桃问题:每天都吃了前一天剩下的一半多一个。
  • ​力扣解法汇总1802. 有界数组中指定下标处的最大值
  • #gStore-weekly | gStore最新版本1.0之三角形计数函数的使用
  • $nextTick的使用场景介绍
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (分享)自己整理的一些简单awk实用语句
  • (十七)Flask之大型项目目录结构示例【二扣蓝图】
  • (图)IntelliTrace Tools 跟踪云端程序
  • (转)MVC3 类型“System.Web.Mvc.ModelClientValidationRule”同时存在
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .NET Core 版本不支持的问题
  • .sh
  • /dev下添加设备节点的方法步骤(通过device_create)
  • @Resource和@Autowired的区别
  • [2010-8-30]
  • [2016.7 Day.4] T1 游戏 [正解:二分图 偏解:奇葩贪心+模拟?(不知如何称呼不过居然比std还快)]
  • [2023-年度总结]凡是过往,皆为序章
  • [AIGC] CompletableFuture的重要方法有哪些?
  • [BUUCTF]-Reverse:reverse3解析
  • [BZOJ] 3262: 陌上花开
  • [bzoj2957]楼房重建
  • [codeforces]Levko and Permutation
  • [Docker]十二.Docker consul集群搭建、微服务部署,Consul集群+Swarm集群部署微服务实战
  • [Excel] vlookup函数
  • [iOS]-网络请求总结
  • [Linux系统编程] 静态库与动态库