进程间的通信方式

进程间的通信方式

  • 进程间的通信方式
    • 管道(pipe)
    • 命名管道(named pipe)
    • 信号(signal)
    • 消息队列(message queue)
    • 共享内存(shared memory)
    • 信号量(semaphore)
    • 套接字(socket)
      • 类型
      • 协议
      • 基于流套接字的客户/服务器的工作流程

进程间的通信方式

进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。

进程是分配系统资源的单位,包括内存地址空间,为了保证安全,一个进程不能直接访问另一个进程的地址空间。因此各进程拥有的内存地址空间相互独立。

但是进程之间的信息交换又是必须实现的。为了保证进程间的安全通道,操作系统提供了一些方法。
那么不同进程之间存在着什么双方都可以访问的介质呢?进程的用户空间是互相独立的,一般而言是不能互相访问的,唯一的例外是共享内存区。但是,系统空间却是“公共场所”,所以内核显然可以提供这样的条件。除此以外,那就是双方都可以访问的外设了。在这个意义上,两个进程当然也可以通过磁盘上的普通文件交换信息,或者通过“注册表”或其它数据库中的某些表项和记录交换信息。广义上这也是进程间通信的手段,但是一般都不把这算作“进程间通信”。因为那些通信手段的效率太低了,而人们对进程间通信的要求是要有一定的实时性。

和常见的通信一样,进程间的通信也主要是为了处理以下几种情况:

  1. 数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几兆字节之间。
  2. 共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。
  3. 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
  4. 资源共享:多个进程之间共享同样的资源。为了做到这一点,需要内核提供锁和同步机制。
  5. 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

进程通过与内核及其它进程之间的互相通信来协调它们的行为。如Linux支持多种进程间通信机制,信号和管道是其中的两种。除此之外,Linux还支持System V的进程间通信机制。

进程间通信是同一台处理机或不同处理机的多个进程间传送数据或消息的一些技术或方法,主要的方式有:

管道(pipe)

管道,通常指无名管道。

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

特点:

  1. 它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端。
  2. 它只能用于具有亲缘关系的进程之间的通信(父子进程或者兄弟进程之间)。
  3. 它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。

管道进程通信步骤:

  1. 父进程创建管道,得到两个⽂件描述符指向管道的两端。
    在这里插入图片描述

  2. 父进程fork出子进程,⼦进程也有两个⽂件描述符指向同⼀管道。
    在这里插入图片描述

  3. 父进程关闭fd[0],子进程关闭fd[1],即⽗进程关闭管道读端,⼦进程关闭管道写端(因为管道只支持单向通信)。⽗进程可以往管道⾥写,⼦进程可以从管道⾥读,管道是⽤环形队列实现的,数据从写端流⼊从读端流出,这样就实现了进程间通信。
    在这里插入图片描述

命名管道(named pipe)

命名管道(FIFO)又叫有名管道,和无名管道的主要区别在于,命名管道有一个名字,命名管道的名字对应于一个磁盘索引节点,但没有数据块,有了这个文件名,任何进程有相应的权限都可以对它进行访问。

特点:

  1. FIFO可以在无关的进程之间交换数据,与无名管道不同。
  2. FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。

通过mknode()系统调用或者mkfifo()函数来建立对一个FIFO的访问权限:

#include <sys/stat.h>
// 返回值:成功返回0,出错返回-1
int mkfifo(const char *pathname, mode_t mode);

一旦创建了一个 FIFO,就可以用一般的文件I/O函数操作它。比如可以使用open()函数通过文件名可以打开已经创建的命名管道,也可以用删除普通文件的方法将其删除,实际删除的事磁盘上对应的节点信息。

命名管道也是半双工的通信方式,命名管道除了具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。

信号(signal)

信号是一种比较复杂的通信方式,是在软件层次上对中断机制的一种模拟,它是一种异步通信方式(也是进程通信中唯一一个异步的通信方式),也是比较复杂的通信方式,用于通知进程有某事件发生,一个进程收到一个信号与处理器收到一个中断请求效果上可以说是一致的。

信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。

如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行
再传递给它。如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。

常用信号有以下几种:

  1. SIGHUP:终止信号,该信号在用户终端连接结束时发出,通常是在终端的控制进程结束时,通知同一会话内的各个作业与控制端不再关联;
  2. SIGINT:终止信号,该信号在用户输入intr字符,通常是ctrl+c时发出,终端驱动程序发出此信号并送到前台进程中的每一个进程;
  3. SIGQUIT:终止信号,该信号和SIGINT信号类似,但是由quit字符,通常是ctrl+\来控制;
  4. SIGALRM:闹钟信号,该信号当一个定时器到时的时候发出,收到此信号后定时结束,结束进程;
  5. SIGCHLD:忽略信号,子进程状态改变,父进程会收到这个信号
  6. SIGKILL:杀死信号,该信号用来立即结束程序的运行,并且不能被阻塞、处理和忽略;
  7. SIGFPE:终止信号,该信号在发生比较严重的算术运算错误时发出;
  8. SIGILL:终止信号,该信号在一个进程企图执行一条非法指令时发出,比如可执行文件出现错误堆栈溢出时等等;

用户进程对信号的响应方式主要有三种:

  1. 忽略信号:就是对信号不做任何处理,但是有两个信号不能忽略:SIGKILL及SIGSTOP。
  2. 捕捉信号:定义信号处理函数,当信号发生时,执行相应的处理函数。
  3. 执行缺省操作:Linux对每种信号都规定了默认操作。

信号使用主要有以下几个步骤:

  1. 在目的进程中安装信号,需要提供一个信号处理函数。
  2. 信号被某个进程产生。
  3. 操作系统响应信号,在目的进程中被注册。(信号在目的进程中被注册,操作系统将添加信号到目的进程的PCB的未决信号数据结构中)。
  4. 信号在进程中注销,进程在执行信号处理函数之前,首先要把信号在进程中注销。
  5. 信号生命终止,保护上下文,进程捕获信号,即执行信号处理函数。

消息队列(message queue)

消息队列,就是一个消息的链表,是一系列保存在内核中消息的列表,存放在内核中并由消息队列标识符(即队列ID)标识。

特点:

  1. 消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
  2. 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
  3. 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。

消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。 每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。可以通过发送消息来避免命名管道的同步和阻塞问题。但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制。

消息队列也克服了管道通信方式中信号量有限的缺点,具有写权限的进程可以按照一定的规则向消息队列中添加新信息;对消息队列有读权限的进程则可以从消息队列中读取信息。

消息队列与管道通信相比,其优势是对每个消息指定特定的消息类型,接收的时候不需要按照队列次序,而是可以根据自定义条件接收特定类型的消息。

可以把消息看做一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息,对消息队列有读权限的进程可以从消息队列中读取消息。

进程间通过消息队列通信,主要是:创建或打开消息队列,添加消息,读取消息和控制消息队列。

共享内存(shared memory)

共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制(如信号量)配合使用,来实现进程间的同步和通信。共享内存可以说这是最有用的进程间通信方式。

共享内存允许两个或多个进程共享一个给定的存储区,这一段存储区可以被两个或两个以上的进程映射至自身的地址空间中,一个进程写入共享内存的信息,可以被其他使用这个共享内存的进程,通过一个简单的内存读取读出,从而实现了进程间的通信。这种方式需要依靠某种同步操作,如互斥锁和信号量等。

特点:

  1. 共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。
  2. 因为多个进程可以同时操作,所以需要进行同步。
  3. 信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。

采用共享内存进行通信的一个主要好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝,对于像管道和消息队列等通信方式,则需要再内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次:一次从输入文件到共享内存区,另一次从共享内存到输出文件。

一般而言,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时在重新建立共享内存区域;而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件,因此,采用共享内存的通信方式效率非常高。

但是,共享内存也并不完美,共享内存并未提供同步机制,也就是说,在一个服务进程结束对共享内存的写操作之前,并没有自动机制可以阻止另一个进程开始对它进行读取。这明显还达不到我们想要的,我们不单是在两进程间交互数据,还想实现多个进程对共享内存的同步访问,这也正是使用共享内存的窍门所在。所以,我们通常会用信号量来实现对共享内存同步访问控制。

信号量(semaphore)

信号量本质上是一个计数器,它和管道有所不同,它不以传送数据为主要目的,主要作为进程之间及同一种进程的不同线程之间的同步和互斥手段,它常作为一种锁机制,可以用来控制多个进程对共享资源的访问,防止某进程正在访问共享资源时,其他进程也访问该资源,使得资源在一个时刻只有一个进程独享。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),它们之间的关系如下:

  1. P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行。
  2. V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1。

因为信号量属于临界资源,为了保护临界资源,信号量进行PV操作时都为原子操作。

套接字(socket)

socket即套接字,它是一种通信机制,凭借这种机制,客户/服务器(即要进行通信的进程)系统的开发工作既可以在本地单机上进行,也可以跨网络进行。也就是说它可以让不在同一台计算机但通过网络连接计算机上的进程进行通信。也因为这样,套接字明确地将客户端和服务器区分开来。

前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,套接字socket也是一种进程间通信机制,与其他通信机制不同的是,使用socket进行通信的进程可以是同一台计算机的进程,也是可以是通过网络连接起来的不同计算机上的进程,它可用于网络中不同机器之间的进程间通信,应用非常广泛。

套接字的特性由3个属性确定,它们分别是:域、类型和协议。

它指定套接字通信中使用的网络介质,最常见的套接字域是AF_INET,它指的是Internet网络。当客户使用套接字进行跨网络的连接时,它就需要用到服务器计算机的IP地址和端口来指定一台联网机器上的某个特定服务,所以在使用socket作为通信的终点,服务器应用程序必须在开始通信之前绑定一个端口,服务器在指定的端口等待客户的连接。另一个域AF_UNIX表示UNIX文件系统,它就是文件输入/输出,而它的地址就是文件名。

类型

因特网提供了两种通信机制:流(stream)和数据报(datagram),因而套接字的类型也就分为流套接字和数据报套接字。进程使用流套接字进行通信。

流套接字由类型SOCK_STREAM指定,它们是在AF_INET域中通过TCP/IP连接实现,同时也是AF_UNIX中常用的套接字类型。流套接字提供的是一个有序、可靠、双向字节流的连接,因此发送的数据可以确保不会丢失、重复或乱序到达,而且它还有一定的出错后重新发送的机制。

与流套接字相对的是由类型SOCK_DGRAM指定的数据报套接字,它不需要建立连接和维持一个连接,它们在AF_INET中通常是通过UDP/IP协议实现的。它对可以发送的数据的长度有限制,数据报作为一个单独的网络消息被传输,它可能会丢失、复制或错乱到达,UDP不是一个可靠的协议,但是它的速度比较高,因为它需要总是要建立和维持一个连接。

协议

只要底层的传输机制允许不止一个协议来提供要求的套接字类型,我们就可以为套接字选择一个特定的协议。通常只需要使用默认值。

基于流套接字的客户/服务器的工作流程

  1. 首先服务器应用程序用系统调用socket来创建一个套接字,它是系统分配给该服务器进程的类似文件描述符的资源,它不能与其他的进程共享。
  2. 接下来,服务器进程会给套接字起个名字,使用系统调用bind来给套接字命名。然后服务器进程就开始等待客户连接到这个套接字。
  3. 然后,系统调用listen来创建一个队列并将其用于存放来自客户的进入连接。
  4. 最后,服务器通过系统调用accept来接受客户的连接。它会创建一个与原有的命名套接不同的新套接字,这个套接字只用于与这个特定客户端进行通信,而命名套接字(即原先的套接字)则被保留下来继续处理来自其他客户的连接。
  5. 基于socket的客户端比服务器端简单,同样,客户应用程序首先调用socket来创建一个未命名的套接字,然后将服务器的命名套接字作为一个地址来调用connect与服务器建立连接。
  6. 一旦连接建立,就可以像使用底层的文件描述符那样用套接字来实现双向数据的通信。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

回溯dfs和分支限界bfs

一&#xff1a;拓扑排序 207. 课程表 这道题说白了就是在有向图中找环 拓扑排序实际上应用的是贪心算法。 贪心算法简而言之&#xff1a;每一步最优&#xff0c;全局就最优。 每一次都从图中删除没有前驱的顶点&#xff0c;这里并不需要真正的删除操作&#xff0c;通过设置入度…

Solana 2024 投资新风口:挖掘 DeFi、硬件开发与交易创新

将区块链的技术红利带给所有用户&#xff0c;Solana 自 2017 年诞生以来就致力于赋予开发者、消费者、投资人等各路人士的优越应用体验。在“以太坊杀手”林立的公链竞争阶段&#xff0c;Solana 凭借高性能公链的独特定位&#xff0c;朝着去中心化、安全性、低成本的目标不断精…

SpringBoot实现RabbitMQ的定向交换机(SpringAMQP 实现Direct定向交换机)

文章目录 Direct 交换机特点实战声明交换及其队列(以注解方式)发消息 应用 上一篇文章中的 Fanout 模式&#xff0c;一条消息&#xff0c;会被所有订阅其交换机的队列都消费。 但是&#xff0c;在某些场景下&#xff0c;我们希望不同的消息被不同的队列消费。这时就要用到 Dir…

蓝桥杯day14刷题日记

P8707 [蓝桥杯 2020 省 AB1] 走方格 思路&#xff1a;很典型的动态规划问题&#xff0c;对于偶数格特判&#xff0c;其他的正常遍历一遍&#xff0c;现在所处的格子的方案数等于左边的格子的方案数加上上面格子的方案数之和 #include <iostream> using namespace std; …

WPF 路由事件 数据驱动 、Window 事件驱动

消息层层传递&#xff0c;遇到安装有事件侦听器的对象&#xff0c;通过事件处理器响应事件&#xff0c;并决定事件是否继续传递&#xff1b; 后置代码中使用AddHandler方法设置事件监听器&#xff0c;该方法的 第一个参数是指定监听的路由事件类型对象&#xff0c; 第二个参数…

企业数据资产管理的战略价值与实施策略

一、引言 数据资产不仅记录了企业的历史运营情况&#xff0c;更能够揭示市场的未来趋势&#xff0c;为企业的决策提供有力支持。因此&#xff0c;如何有效地管理和利用数据资产&#xff0c;已经成为企业竞争力的重要体现。本文将探讨企业数据资产管理的战略价值与实施策略&…

新能源充电桩站场视频汇聚系统建设方案及技术特点分析

随着新能源汽车的普及&#xff0c;充电桩作为新能源汽车的基础设施&#xff0c;其安全性和可靠性越来越受到人们的关注。为了更好地保障充电桩的安全运行与站场管理&#xff0c;TSINGSEE青犀&触角云推出了一套新能源汽车充电桩视频汇聚管理与视频监控方案。 方案采用高清摄…

SMART PLC温度变化率计算功能块(算法框图+代码)

SMART PLC文章控制专用PID请参考下面文章链接: https://rxxw-control.blog.csdn.net/article/details/136702516https://rxxw-control.blog.csdn.net/article/details/136702516 1、监控下温度变化率 2、温度变化率计算功能块 3、计算周期到达

PCA+DBO+DBSCN聚类,蜣螂优化算法DBO优化DBSCN聚类,适合学习,也适合发paper!

PCADBODBSCN聚类&#xff0c;蜣螂优化算法DBO优化DBSCN聚类&#xff0c;适合学习&#xff0c;也适合发paper&#xff01; 一、蜣螂优化算法 摘要&#xff1a;受蜣螂滚球、跳舞、觅食、偷窃和繁殖等行为的启发&#xff0c;提出了一种新的基于种群的优化算法(Dung Beetle Optim…

BGP实训

BGP基础配置实训 实验拓扑 注&#xff1a;如无特别说明&#xff0c;描述中的 R1 或 SW1 对应拓扑中设备名称末尾数字为 1 的设备&#xff0c;R2 或 SW2 对应拓扑中设备名称末尾数字为2的设备&#xff0c;以此类推&#xff1b;另外&#xff0c;同一网段中&#xff0c;IP 地址的主…

Harbor部署

Harbor部署 下载和安装 github下载地址&#xff1a;https://github.com/goharbor/harbor/releases 解压和配置 # 解压tgz包 tar -zxvf harbor-offline-installer-v2.10.1.tgz # 进入目录后进行复制配置文件 cd harbor/ # 创建一个配置文件 cp harbor.yml.tmpl harbor.yml …

RabbitMQ基础笔记

视频链接&#xff1a;【黑马程序员RabbitMQ入门到实战教程】 文章目录 1.初识MQ1.1.同步调用1.2.异步调用1.3.技术选型 2.RabbitMQ2.1.安装2.1.1 Docker2.1.1 Linux2.1.1 Windows 2.2.收发消息2.2.1.交换机2.2.2.队列2.2.3.绑定关系2.2.4.发送消息 2.3.数据隔离2.3.1.用户管理2…

金三银四面试题(七):JVM常见面试题(1)

JVM会有许多零碎但是却很高频的基础考题。牢记这些&#xff0c;才能保证不在面试中落后于人。 说说对象分配规则 这也是之前面试腾讯时候被问到的问题&#xff1a;请介绍JVM如何分配对象&#xff1f; 对象优先分配在Eden 区&#xff0c;如果Eden 区没有足够的空间时&#xf…

nysm:一款针对红队审计的隐蔽型后渗透安全测试容器

关于nysm nysm是一款针对红队审计的隐蔽型后渗透安全测试容器&#xff0c;该工具主要针对的是eBPF&#xff0c;能够帮助广大红队研究人员在后渗透测试场景下保持eBPF的隐蔽性。 功能特性 随着基于eBPF的安全工具越来越受社区欢迎&#xff0c;nysm也应运而生。该工具能保持各种…

简单线程池的实现

线程池的代码可以写的很复杂&#xff0c;这里就稍微简单一些 首先来看一下线程池的原则&#xff0c;下面的大框是服务器&#xff0c;而在服务器中维护一个任务队列。 然后在server中预先创建一批线程&#xff0c;这批线程和任务队列合在一起只用向外界提供一个入队列的接口。 …

【php程序开发从入门到精通】——搭建PHP开发环境

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

搜索与图论——Floyd算法求最短路

floyd算法用来求多源汇最短路 用邻接矩阵来存所有的边 时间复杂度O(n^3) #include<iostream> #include<cstring> #include<algorithm>using namespace std;const int N 20010,INF 1e9;int n,m,k; int g[N][N];void floyd(){for(int k 1;k < n;k ){f…

计算机网络(第八版)-第1章课后习题参考答案

计算机网络(第八版)-第1章课后习题参考答案 本文是对自己之前文章的格式化&#xff1a;https://blog.csdn.net/qq_46396470/article/details/132788972?spm1001.2014.3001.5502 T1-01 计算机网络向用户可以提供哪些服务&#xff1f; 连通性和共享 &#xff0c;例如音频&…

docker环境配置过程中的常见问题

1、pull镜像问题 docker pull jenkins/jenkins:lts Using default tag: latest Trying to pull repository docker.io/library/centos ... Get https://registry-1.docker.io/v2/library/centos/manifests/latest: Get https://auth.docker.io/token?scoperepository%3Alibr…

基于Spring Boot 3 + Spring Security6 + JWT + Redis实现接口资源鉴权

紧接上一篇文章&#xff0c;基于Spring Boot 3 Spring Security6 JWT Redis实现接口资源鉴权 系列文章指路&#x1f449; 系列文章-基于SpringBoot3创建项目并配置常用的工具和一些常用的类 项目源码&#x1f449; /shijizhe/boot-test 文章目录 1. 修改 UserDetailsServic…