深入探讨进程间通信的重要性:理解不同的通信机制(上)

深入探讨,进程,间通信,重要性,理解,不同,通信,机制 · 浏览次数 : 511

小编点评

**进程间通信机制** **管道** - 将一个进程的输出直接作为另一个进程的输入。 - 使用 `mkfifo` 创建管道文件,并在进程之间传递数据。 - 管道只能在具有父子关系的进程之间进行通信。 **消息队列** - 是一种进程间通信机制,通过在内核中创建一个消息链表来实现。 - 进程可以将数据放入消息队列中,其他进程可以从队列中读取这些数据。 - 消息队列可以支持进程间的异步通信,并具有更高的效率和灵活性。 **共享内存** - 进程可以共享同一块内存区域,避免了数据的复制过程。 - 效率高,但需要通过同步机制来保证数据一致性。 **其他机制** - **信号量:**用于通知进程进行特定事件的通知。 - **信号:**用于进程之间的通信,允许进程向其他进程发送和接收信号。 - **套接字:**用于两台系统之间进行通信的特殊通信机制。

正文

进程间通信

在操作系统中,进程间通信是指不同进程之间进行信息共享、数据传输和消息通知等交互的过程。每个进程在创建时都有自己独立的虚拟地址空间,但它们共享内核空间。因此,要实现进程间的通信,必须通过内核来进行中介,如下图所示:

image

在Linux系统中,提供了多种进程间通信的机制,包括管道、消息队列、共享内存、信号量、信号、套接字等。这些机制允许进程之间共享数据、传输消息以及进行进程间的同步与通信。下面我们详细讲解下。

管道

管道是一种进程间通信机制,它可以将一个进程的输出直接作为另一个进程的输入。在Linux系统中,管道可以用于将命令的输出传递给另一个命令进行处理。

ps -ef |grep java

使用Linux系统练手的时候,想必大家都是用这样的一种命令查看java进程,命令中的 | 就是管道命令,但是这个是匿名管道,用完了就销毁,匿名管道只能在有父子关系的进程之间进行通信。他的功能也很好理解,一个进程的输出直接作为另一个进程的输入,所以才能只展现java进程,所以他的传输方式是单向传输。

那么既然有匿名管道,就有命名管道,被叫做 FIFO,因为数据是先进先出的传输方式。命名管道具有读写两个端口,进程可以通过打开管道的文件来进行读取或写入。当一个进程写入数据到管道时,另一个进程可以从管道中读取数据。

在使用命名管道前,先需要通过 mkfifo 命令来创建,并且指定管道名字:

$ mkfifo myPipe

myPipe 是管道的名称,在 Linux 中一切皆文件的原则下,管道也以文件的形式存在。我们可以使用 ll 命令查看一下,该文件的类型是 p,表示为管道(pipe)。

image

接下来,我们将数据写入名为 myPipe 的管道中:

image

在执行完写入操作后,你可能会发现命令执行后一直停留在那里。这是因为管道中的数据没有被读取,只有当管道中的数据被完全读取后,命令才能正常退出。因此,我们需要执行另一个命令来读取管道中的数据:

image

可以观察到,管道中的内容已经被成功读取并打印在终端上,另外,echo命令也正常退出了。

从中我们可以得知,匿名管道的通信范围限定在具有父子关系的进程之间。由于管道本身没有实体,也就是没有管道文件,所以只能通过fork来复制父进程的文件描述符,以实现进程间的通信。(fork是一个操作系统调用,用于创建一个新的进程。当调用fork时,操作系统会复制当前进程的副本)

image

在shell中执行A | B命令时,A进程和B进程都是由shell创建的子进程。A和B之间不存在父子关系,它们的父进程都是shell。

image

此外,对于命名管道,它可以在不相关的进程之间进行通信。这是因为命名管道事先创建了一个特定类型的设备文件,在进程中只需要使用该设备文件,就可以实现进程之间的通信。

消息队列

消息队列是一种进程间通信的机制,它相比于管道具有更高的效率和灵活性。消息队列是通过在内核中创建一个消息链表来实现的,进程可以将数据放入消息队列中,然后其他进程可以从队列中读取这些数据。

例如,当进程A需要向进程B发送消息时,进程A将数据放入B进程对应的消息队列后即可正常返回。而进程B可以在需要时去读取数据。同样地,当进程B需要向进程A发送消息时,也可以按照相同的方式进行操作。

与管道不同的是,消息队列是有格式的,每个消息体都是固定大小的存储块,进程在读取数据时需要约定好消息体的数据类型。消息队列的优势在于可以支持进程间的异步通信,发送方和接收方不需要同时运行,消息可以在队列中等待对方读取。不像管道是无格式的字节流数据。如果进程从消息队列中读取了消息体,内核就会把这个消息体删除。

image

消息队列的生命周期与内核相关,如果没有显式地释放消息队列或关闭操作系统,消息队列将一直存在。而管道的生命周期是随着进程的创建和结束而动态建立和销毁。

然而,消息队列也存在一些缺点。由于数据在用户态和内核态之间进行拷贝,消息队列通信过程中存在一定的开销。当进程将数据写入消息队列时,需要将数据从用户态拷贝到内核态;而另一个进程从消息队列中读取数据时,需要将数据从内核态拷贝到用户态。这种数据拷贝开销会影响通信的效率。

共享内存

共享内存是一种高效的进程间通信机制,它允许多个进程共享同一块内存区域,避免了数据的拷贝过程,提高了通信速度。

在共享内存机制中,操作系统将一块共享内存区域映射到多个进程的虚拟地址空间中,使得它们可以直接访问同一块物理内存。这样,一个进程对共享内存的写入操作,其他进程可以立即看到更新后的数据,而不需要进行数据的拷贝传输。

由于共享内存不进行数据拷贝,因此在进程间通信的过程中,它具有较低的开销和较高的传输速度。然而,共享内存机制需要通过同步机制来保证多个进程之间的数据一致性,以免出现竞争条件和数据不一致的问题。

image

总结

本篇文章总结了进程间通信的三种常见机制:管道、消息队列和共享内存。它介绍了每种机制的特点、优缺点以及适用场景。管道适用于父子进程之间的通信,但只能在有亲缘关系的进程之间使用。消息队列可以用于异步通信,并且支持多个进程之间的通信,但是消息的格式需要事先定义。共享内存是一种高效的通信方式,可以实现多个进程共享同一块内存区域,但需要处理进程间的同步和互斥。根据实际需求,可以选择合适的机制进行进程间通信。

下一篇文章将继续探讨信号量、信号和套接字的知识点!

与深入探讨进程间通信的重要性:理解不同的通信机制(上)相似的内容:

深入探讨进程间通信的重要性:理解不同的通信机制(上)

本文旨在探讨进程间通信的重要性,并介绍了不同的通信机制,如管道、消息队列、共享内存、信号量、信号和套接字。通过理解这些通信机制的特点和应用场景,可以更好地实现进程间的高效数据共享。同时,本文还强调了同步和互斥机制的重要性,以确保数据的一致性和正确性。最后,还介绍了套接字作为一种跨网络和同一主机上进程间通信的通信机制,为读者提供了更全面的了解。通过阅读本文,读者将能够深入理解进程间通信的概念和不同机制,为实现有效的数据共享提供指导。

深入探讨进程间通信的重要性:理解不同的通信机制(下)

本文旨在探讨进程间通信的重要性,并介绍了不同的通信机制,如管道、消息队列、共享内存、信号量、信号和套接字。通过理解这些通信机制的特点和应用场景,可以更好地实现进程间的高效数据共享。同时,本文还强调了同步和互斥机制的重要性,以确保数据的一致性和正确性。最后,还介绍了套接字作为一种跨网络和同一主机上进程间通信的通信机制,为读者提供了更全面的了解。通过阅读本文,读者将能够深入理解进程间通信的概念和不同机制,为实现有效的数据共享提供指导。

14.2 Socket 反向远程命令行

在本节,我们将继续深入探讨套接字通信技术,并介绍一种常见的用法,实现反向远程命令执行功能。对于安全从业者而言,经常需要在远程主机上执行命令并获取执行结果。本节将介绍如何利用 `_popen()` 函数来启动命令行进程,并将输出通过套接字发送回服务端,从而实现远程命令执行的功能。在实现反向远程命令执行时,我们可以使用 `_popen(buf, "r")` 函数来执行特定的命令,并将其输出重定向到一个

从数据链路到神秘的MAC地址和ARP协议

在当今互联世界中,数据的传输和通信是不可或缺的。然而,你是否曾想过,在网络通信中隐藏着哪些神秘的秘密?本文将带你深入探索数据链路层、MAC地址和ARP协议的奥秘。数据链路层是网络通信中的关键一环,负责将数据包封装为帧并进行传输。而MAC地址作为设备的唯一标识符,扮演着识别节点的重要角色。而ARP协议则解决了从IP地址到MAC地址的映射问题,确保数据的准确传输。通过揭开这些网络通信的神秘面纱,你将更

[转帖]深入理解同步机制---内核自旋锁

https://switch-router.gitee.io/blog/spinlock/ 进程(线程)间的同步机制是面试时的常见问题,所以准备用一个系列来好好整理下用户态与内核态的各种同步机制。本文就以内核空间的一种基础同步机制—自旋锁开始好了 自旋锁是什么 自旋锁就是一个二状态的原子(atomi

跨主机Docker容器通信的学习

背景 骨折在家找自己的人比较少. 又因为出不去也没法做运动,就不如将之前没学习深入的地方学习下 先是进行Docker 搭建 redis cluster的处理. 当时发现必须使用 --net=host进行. 本来想尝试进行 overlay的网咯进行搭建 当然有一个目的是验证 overlay的性能损耗

深入理解 Vue 3 组件通信

在 Vue 3 中,组件通信是一个关键的概念,它允许我们在组件之间传递数据和事件。本文将介绍几种常见的 Vue 3 组件通信方法,包括 props、emits、provide 和 inject、事件总线以及 Vuex 状态管理。 1. 使用 props 和 emits 进行父子组件通信 props

< Python全景系列-5 > 解锁Python并发编程:多线程和多进程的神秘面纱揭晓

深入探讨Python中的并发编程,特别关注多线程和多进程的应用。我们将先从基本概念开始,然后通过详细举例探讨每一种机制,最后分享一些实战经验以及一种优雅的编程技巧。

一文掌握Python多线程与多进程

# Python的多线程和多进程 ## 一、简介 并发是今天计算机编程中的一项重要能力,尤其是在面对需要大量计算或I/O操作的任务时。Python 提供了多种并发的处理方式,本篇文章将深入探讨其中的两种:多线程与多进程,解析其使用场景、优点、缺点,并结合代码例子深入解读。 ## 二、多线程 Pyth

Java开发者的神经网络进阶指南:深入探讨交叉熵损失函数

在本文中,我们深入探讨了交叉熵函数作为一种重要的损失函数,特别适用于神经网络训练中。交叉熵通过衡量真实标签分布与模型预测分布之间的差异,帮助优化模型的性能。我们从信息论的角度解释了交叉熵的概念,它是基于Shannon信息论中的熵而来,用于度量两个概率分布之间的差异。