面试了这么多场,“ 进程间的通信 ” 真是从不缺席,小伙伴们赶快重视起来!!

2023-11-07

每个进程的用户地址空间都是独立的,一般而言是不能互相访问的,但内核空间是每个进程都共享的,所以进程之间要通信必须通过内核。
在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为 进程间通信
在这里插入图片描述

在这里插入图片描述


1、管道:

匿名管道:
  • 管道是单向的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道。
  • 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
  • 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
  • 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。
  • 效率低,不适合频繁交换数据
    在这里插入图片描述

管道的实质:

  • 管道的实质是一个内核缓冲区,进程以先进先出的方式从缓冲区存取数据,管道一端的进程顺序的将数据写入缓冲区,另一端的进程则顺序的读出数据。
  • 该缓冲区可以看做是一个循环队列,读和写的位置都是自动增长的,不能随意改变,一个数据只能被读一次,读出来以后在缓冲区就不复存在了。
  • 当缓冲区读空或者写满时,有一定的规则控制相应的读进程或者写进程进入等待队列,当空的缓冲区有新数据写入或者满的缓冲区有数据读出来时,就唤醒等待队列中的进程继续读写。

管道的局限:

  • 只支持单向数据流;
  • 只能用于具有亲缘关系的进程之间;
  • 没有名字;
  • 管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小);
  • 管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,比如多少字节算作一个消息(或命令、或记录)等等;
有名管道:

匿名管道,由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道

  • 有名管道 不同于匿名管道之处在于它 提供了一个路径名 与之关联,以有名管道的文件形式存在于文件系统中,这样,即使与有名管道的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过有名管道相互通信,因此,通过有名管道不相关的进程也能交换数据。值的注意的是,有名管道严格遵循 先进先出 ,对匿名管道及有名管道的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。有名管道的名字存在于文件系统中,内容存放在内存中。
总结:
  • 在 shell 里通过「|」匿名管道将多个命令连接在一起,实际上也就是创建了多个子进程,那么在我们编写 shell 脚本时,能使用一个管道搞定的事情,就不要多用一个管道,这样可以减少创建子进程的系统开销。
  • 对于匿名管道,它的通信范围是存在父子关系的进程。因为管道没有实体,也就是没有管道文件,只能通过 fork 来复制父进程 fd 文件描述符,来达到通信的目的。
  • 对于命名管道,它可以在不相关的进程间也能相互通信。因为命令管道,提前创建了一个类型为管道的设备文件,在进程里只要使用这个设备文件,就可以相互通信。
  • 不管是匿名管道还是命名管道,进程写入的数据都是缓存在内核中,另一个进程读取数据时候自然也是从内核中获取,同时通信数据都遵循先进先出原则,不支持 lseek 之类的文件定位操作

2、消息队列:

A 进程要给 B 进程发送消息,A 进程把数据放在对应的消息队列后就可以正常返回了,B 进程需要的时候再去读取数据就可以了。同理,B 进程要给 A 进程发送消息也是如此。(就像平时发邮件一样,你来一封,我回一封,可以频繁沟通了。)

  • 消息队列是存放在内核中的 消息链表,每个消息队列由消息队列标识符表示。
  • 消息队列允许一个或多个进程向它写入与读取消息。
  • 管道和消息队列的通信数据都是先进先出的原则。
  • 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取.比FIFO更有优势。
  • 消息队列克服了信号承载信息量少,管道只能承载无格式字 节流以及缓冲区大小受限等缺。
  • 目前主要有两种类型的消息队列:POSIX消息队列以及System V消息队列,系统V消息队列目前被大量使用。系统V消息队列是随内核持续的,只有在内核重起或者人工删除时,该消息队列才会被删除。

缺点:

  • 消息队列 不适合大数据的传输,因为在内核中每个消息体都有一个最大长度的限制,同时所有队列所包含的全部消息体的总长度也是有上限。在 Linux 内核中,会有两个宏定义 MSGMAX 和 MSGMNB,它们以字节为单位,分别定义了一条消息的最大长度和一个队列的最大长度。
  • 消息队列通信过程中,存在用户态与内核态之间的数据拷贝开销,因为进程写入数据到内核中的消息队列时,会发生从用户态拷贝数据到内核态的过程,同理另一进程读取内核中的消息数据时,会发生从内核态拷贝数据到用户态的过程。

与管道的比较:

管道 消息队列
无名管道:只存在于内存中的文件;命名管道:存在于实际的磁盘介质或者文件系统 存放在内核中
用完就被删除 有在内核重启或者显示地删除一个消息队列时,该消息队列才会被真正的删除。
随进程的创建而建立,随进程的结束而销毁 在某个进程往一个队列写入消息之前,并不需要另外某个进程在该队列上等待消息的到达。

3、共享内存:

消息队列 的读取和写入的过程,都会有 发生用户态与内核态之间的消息拷贝过程共享内存 的方式,就很好的解决了这一问题。

现代操作系统,对于内存管理:采用的是 虚拟内存技术。也就是每个进程都有自己独立的虚拟内存空间,不同进程的虚拟内存映射到不同的物理内存中。所以,即使进程 A 和 进程 B 的虚拟地址是一样的,其实访问的是不同的物理内存地址,对于数据的增删查改互不影响。

共享内存的机制,就是拿出一块虚拟地址空间来,映射到相同的物理内存中。这样这个进程写入的东西,另外一个进程马上就能看到了,都不需要拷贝来拷贝去,传来传去,大大提高了进程间通信的速度。
在这里插入图片描述


4、信号量:

① 用了 共享内存通信方式,带来新的问题:那就是如果 多个进程同时修改同一个共享内存,很有可能就冲突了。例如两个进程都同时写一个地址,那先写的那个进程会发现内容被别人覆盖了。
为了防止多进程竞争共享资源,而造成的数据错乱,所以需要保护机制,使得共享的资源,在任意时刻只能被一个进程访问。正好,信号量就实现了这一保护机制。

信号量 (表示资源的数量):其实是一个 整型的计数器,主要用于 实现进程间的互斥与同步,而不是用于缓存进程间通信的数据。

② 控制信号量的方式有两种原子操作:(两个操作是必须成对出现)

  • P 操作:信号量 减去 1,相减后如果信号量 < 0,则表明资源已被占用,进程需阻塞等待;相减后如果信号量 >= 0,则表明还有资源可使用,进程可正常继续执行。(用在进入共享资源之前)
  • V 操作:信号量 加上 1,相加后如果信号量 <= 0,则表明当前有阻塞中的进程,于是会将该进程唤醒运行;相加后如果信号量 > 0,则表明当前没有阻塞中的进程;(用在离开共享资源之后)
  • 信号初始化为 1,就代表着是 互斥信号量,它可以保证共享内存在 任何时刻只有一个进程在访问
  • 信号初始化为 0,就代表着是 同步信号量,它可以保证 访问者对资源的有序访问

③ 信号量与互斥量之间的区别:
(在大多数情况下,同步已经实现了互斥)

互斥量 信号量
用于线程的 互斥 用于线程的 同步
互斥:某一资源同时只允许一个访问者对其进行访问(无序的) 同步:在互斥的基础上,通过其它机制实现访问者对资源的有序访问
互斥量值只能为 0/1 信号量值可以为非负整数
一个互斥量只能用于一个资源的互斥访问 信号量可以实现多个同类资源的多线程互斥和同步
互斥量的加锁和解锁必须由同一线程分别对应使用 信号量可以由一个线程释放,另一个线程得到

5、信号:

① 上面的进程间通信,都是常规状态下的工作模式。对于 异常情况 下的工作模式,就需要用「信号」的方式来通知进程。

  • 信号可以在 任何时候 发给某一进程,而无需知道该进程的状态(唯一的异步通信机制)
  • 如果该进程当前并未处于执行状态,则该信号就由内核保存起来,直到该进程回复执行并传递给它为止。
  • 如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消是才被传递给进程

② Linux系统中 常用信号

  • Ctrl+C 产生 SIGINT 信号,表示终止该进程;
  • Ctrl+Z 产生 SIGTSTP 信号,表示停止该进程,但还未结束;
  • Ctrl+\ \ 产生 SIGQUIT信号,表示程序退出

③ 信号来源:

信号是 软件层次 上对中断机制的一种模拟,是一种异步通信方式,信号可以在用户空间进程和内核之间直接交互,内核可以利用信号来通知用户空间的进程发生了哪些系统事件,信号事件主要有两个来源:

  • 硬件来源:用户按键输入Ctrl+C退出、硬件异常如无效的存储访问等。
  • 软件终止:终止进程信号、其他进程调用kill函数、软件异常产生信号。

6、Socket(套接字):

前面提到的 管道、消息队列、共享内存、信号量和信号 都是在 同一台主机上 进行进程间通信,那要想 跨网络与不同主机上的进程之间通信,就需要 Socket 通信了。

Socket是什么呢?

  • Socket是 应用层 与 TCP/IP 协议族通信的 中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

在这里插入图片描述
套接字的特性由3个属性确定,它们分别是:域、端口号、协议类型

根据创建 socket 类型的不同,通信的方式也就不同:
1、针对 TCP 协议通信的 socket 编程模型:
在这里插入图片描述
先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

注意:

  • 服务端调用 accept 时,连接成功了会返回一个已完成连接的 socket,后续用来传输数据。
  • 监听的 socket 和真正用来传送数据的 socket,是「两个」 socket,一个叫作监听 socket,一个叫作已完成连接 socket。
  • 成功连接建立之后,双方开始通过 read 和 write 函数来读写数据,就像往一个文件流里面写东西一样

2、针对 UDP 协议通信的 socket 编程模型:

  • UDP 是没有连接的,所以不需要三次握手,也就不需要像 TCP 调用 listen 和 connect,但是 UDP 的交互仍然需要 IP 地址和端口号,因此也需要 bind。
  • 对于 UDP 来说,不需要要维护连接,那么也就没有所谓的发送方和接收方,甚至都不存在客户端和服务端的概念,只要有一个 socket 多台机器就可以任意通信,因此每一个 UDP 的 socket 都需要 bind。
  • 每次通信时,调用 sendto 和 recvfrom,都要传入目标主机的 IP 地址和端口

3、针对 本地进程间 通信的 socket 编程模型:

  • 本地 socket 的编程接口和 IPv4 、IPv6 套接字编程接口是一致的,可以支持「字节流」和「数据报」两种协议;
  • 本地 socket 的实现效率大大高于 IPv4 和 IPv6 的字节流、数据报 socket 实现;
    对于本地字节流 socket,其 socket 类型是 AF_LOCAL 和 SOCK_STREAM。

对于本地数据报 socket,其 socket 类型是 AF_LOCAL 和 SOCK_DGRAM。

本地字节流 socket 和 本地数据报 socket 在 bind 的时候,不像 TCP 和 UDP 要绑定 IP 地址和端口,而是 绑定一个本地文件,这也就是它们之间的最大区别。

参考引用:
https://www.jianshu.com/p/c1015f5ffa74
https://blog.csdn.net/qq_34827674/article/details/107678226

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

面试了这么多场,“ 进程间的通信 ” 真是从不缺席,小伙伴们赶快重视起来!! 的相关文章

  • 代码随想录算法训练营第十四天

    代码随想录算法训练营第十四天 理论基础 递归遍历 迭代遍历 统一迭代 1 1 理论基础 满二叉树 如果一棵二叉树只有度为0的结点和度为2的结点 并且度为0的结点在同一层上 则这棵二叉树为满二叉树 深度为k 有2 k 1个节点的二叉树 完全二
  • 蚁群算法解决tsp问题

    控制蚁群算法走向的关键是信息素 信息素类似遗传算法的适应性函数 类似退火算法的评价函数 影响着其中一只蚂蚁的下一步的选择 蚂蚁 类似遗传算法的染色体 就是一条解 在tsp问题中蚂蚁的路径就是tsp的解 信息素 评价函数 与路径成反比 蚂蚁数
  • CVPR2022论文列表及地址

    主会 CVPR 2022 Open Access Repository Workshop CVPR 2022 Open Access Repository

随机推荐

  • 游戏开发unity xlua框架知识系列:lua层调用c#层的结构体时,使用了比较大的内存空间

    插眼 在xlua中使用C 的结构体时会使用比较多的空间 具体在使用UnityEngine Vector时发现的 暂时没时间分析为什么会产生比较大的内存 参考 这篇文章里有提 https blog csdn net u011467512 ar
  • r语言对模型输出预测值与实际值计算R2,MS残,RMSE和NRMSD,实现模型评估

    此函数可由模型输出的预测值和实际值计算r2或均方根误差RMSE或归一化后的均方根偏差NRMSD 公式参考吴今朝译 R语言机器学习 323 324页 r2 test lt function y actual y predicted avr y
  • TypeError: Cannot read properties of undefined (reading ***)

    在别的地方看了好几个版本 版本一 1 检查你的data定义的属性是不是没有你用到的这个属性 没有的话就定义一个 如下 template div class he info item span class he label 收货人姓名 spa
  • ioctl 简介及示例

    一 ioctl 简介 ioctl是应用与驱动的常用接口 对字符设备 块设备 及套接字 非常方便扩充新的命令 二 定义 include
  • VS2010和VS2013同时安装visual assist X助手

    安装过程如下 本文以visual assist X10 9 2074 0的版本为例 下载链接 http pan baidu com s 1hsu2cyK 密码为 n7rf 首先安装好VS2010和VS2013 如果之前安装过VA X 则需要
  • 微信内置h5浏览器 getBrandWCPayRequest支付

    目录 getBrandWCPayRequest支付 什么是getBrandWCPayRequest支付 如何使用getBrandWCPayRequest支付 getBrandWCPayRequest支付的特点和优势 结论 WeixinJSB
  • DVWA靶场之XSS通关详解

    原理 XSS漏洞是攻击者将恶意代码注入到合法网页中 当用户浏览该页面时 恶意代码会被执行 从而获取用户敏感信息或进行其他攻击 形成原因 网站对用户输入数据的过滤不严格或不完备 攻击者可以根据这个漏洞向网站提交恶意代码 然后再将这些代码传播给
  • ubuntu18断电后recovering journal一直卡在开机界面

    事故机器 elitebook735 系统 ubuntu18 内核 4 20 发生原因 没电关机了 还是保持电量充足比较好 开机的时候回显示 xxx recovering journal dev 磁盘 clean xxxxx 修复方法 关闭电
  • 读书清单

    作者 犹寒 链接 https www zhihu com question 51265095 answer 129906474 来源 知乎 著作权归作者所有 商业转载请联系作者获得授权 非商业转载请注明出处 本文作者姬十三 文章著作权归原作
  • js 浮动窗效果

    源代码
  • md模板练习

    文本样式 强调文本 强调文本 加粗文本 加粗文本 标记文本 删除文本 引用文本 H2O is是液体 210 运算结果是 1024 列表 项目 项目 项目 项目1 项目2 项目3 计划任务 完成任务 链接 链接 link 图片 带尺寸的图片
  • offer审批被刷的可能性_字节跳动音视频面试一面挂!!!复习半月再战,转拿腾讯offer!...

    缘起 字节跳动的音视频面准备了半个月的样子 当时投了很多厂 但是主要目标还是进字节 但是万万没想到 居然一面就没了下文 一开始觉得起码能撑到个二面 三面 所以有些措不及防 在期间 也陆陆续续收到了其他公司的几个offer 但是都是些小公司
  • 通过JAVA代码对yaml文件进行增加、修改的操作

    近期有个需求 需要通过java代码对yaml文件进行修改或新增 对pom xml文件进行添加依赖或者删除依赖 首先介绍对yaml文件的操作 1 需要引入jar包
  • Java Remote Debug

    Java Remote Debug 简介 如果是本地调试 那么在IDE工具 比如Eclipse 的帮助下 是非常容易的 但是如果想对部署在测试 生产环境中的程序进行调试时 你会怎么办呢 在这种情况下 源码已经被编译为中间代码 因此本地调试肯
  • windeployqt.exe的使用与避坑(windows平台)

    1 介绍 windeployqt exe是Qt自带的工具 用于创建应用程序发布包 简单来说 这个工具可以自动地将某程序依赖的库 资源拷贝到其所在目录 防止程序在其他电脑上运行报找不到库的错误 这里贴上官方文档 https doc qt io
  • 零死角玩转stm32-高级篇之FatFs

    零死角玩转stm32 高级篇之FatFs Rev R0 09 2013年08月05日 教程 评论数 1 被围观 1 579 2 FatFs Rev R0 09 2 1 实验描述及工程文件清单 实验描述 MicroSD卡文件系统 FATFS
  • 前端精度丢失处理

    前端操作数据时 如果数据超出一定范围会出现精度丢失的问题 这是因为 在传输过程中 数据类型被转换成Number Number的精度范围在2 53之间 即 9007199254740991 9007199254740991 超出范围就会造成精
  • visual studio code搭建Java环境 - 一步一个脚印详细教程

    visual studio code搭建Java环境 一 软件安装 二 添加环境变量 三 vscode配置 1 软件本身设置 2 编译环境配置 后记 一 软件安装 visual studio code下载链接 https azure mic
  • java 根据 SVN changeLog 文件 生成增量升级包

    近日在做项目的时候 遇到了个问题 因为本地环境与生产环境 不一致 所以修改之后的代码不能整体打包 放到生产环境 而是只能以增量包的形式升级 手动打包 费时费力 而且容易出错 于是参照网上一些博客开发了一个增量包打包工具 好闲言少叙 上代码
  • 面试了这么多场,“ 进程间的通信 ” 真是从不缺席,小伙伴们赶快重视起来!!

    进程间通信 1 管道 2 消息队列 3 共享内存 4 信号量 5 信号 6 Socket 套接字 每个进程的用户地址空间都是独立的 一般而言是不能互相访问的 但内核空间是每个进程都共享的 所以进程之间要通信必须通过内核 在内核中开辟一块缓冲