面试官问:“请你说说进程间的通信方式有哪些?”
我:“啊,进程间通信,额,额,额”

进程间通信的方式

  • 管道
  • 消息队列
  • 共享内存
  • 信号量
  • 信号
  • Socket

    管道

    1. gaoxi@DESKTOP-298U6LA:~$ ps -ef | grep java
    2. gaoxi 71 9 0 20:09 tty1 00:00:00 grep --color=auto java
    管道就是Linux命令中的 | 管道符。其左右就是将前面一条命令的结果作为下一条命令的入参。这里这种管道符具体来说叫做匿名管道符。

    命名管道符

    命名管道符又称FIFO。可以通过mkfifo命令来创建并指定管道的名字
    image.png
    此时向管道中编辑内容,控制台会卡住等待接收
    image.png
    可以通过cat < 管道名称的方式取出管道中的内容
    image.png

消息队列

消息队列这种方式的具体如何使用小林并没有给出具体的用法。这里我提取中几个重点的介绍

  • 消息队列通信过程中,存在内核态与用户态之间的数据拷贝开销

    共享内存

    共享内存的方式顾名思义,就是两个进程都可以操作的一块物理内存。我们知道,每个进程都是使用自己的虚拟内存。虚拟内存最终映射到具体的物理内存。进程A和进程B在没有沟通必要的时候,各自的虚拟内存映射的物理内存是不同的。那么若想存在共享内存的话,就必须将进程A和进程B的某一块虚拟内存映射到相同的一块物理内存上。这样进程A对这块内存的读写对于进程B也是可见的。这就完成了进程间的通信。
    image.png

    信号量

    小林说:“信号量其实就是一个整型的计数器”。
    两个主要的操作:
    P:信号量-1,如果P操作后信号量小于0 阻塞
    V:信号量+1,若V操作后信号量 <= 0 唤醒阻塞进程
    特殊的信号量
    信号量为1:互斥信号量
    信号量为0:同步信号量,就是两个线程V线程走完,P线程走

信号

信号用于异常情况下的通信。Linux提供了几十种信号,可以通过kill -l的方式查看
image.png
CTRL+C:对应图中2
CTRL+Z:对应图中20
信号是进程间通信机制中唯一的异步通信机制,用户进程对于这些信号的处理方式有以下几种:

  • 执行默认操作:每个信号需要执行什么操作都是固定好的
  • 捕捉信号:可以信号发生时,执行对应自定义函数(进程中的)
  • 忽略信号:可以忽略信号,但是9和SEGSTOP不可忽略

    Socket

    Socket主要用于两个不同主机间的进程进行通信,但是同一个主机的两个进程也可以通过Socket通信,但是这就好像,面对面坐的两个人,在用手机打电话。额,形象的比喻。

    针对TCP协议通信的Socket编程模型

    这里全用小林的图了,小林 yyds好吧
    image.png
  1. 服务端初始化Socket,得到文件描述符(万物皆文件)
  2. 服务端调用bind,将主机的ip和端口绑定
  3. 服务端调用listen,进行监听
  4. 服务端调用accept,等待客户端连接
  5. 客户端初始化socket,并调用connect想服务端请求
  6. 服务端accept返回用于传输的socket文件描述符(服务端返回给客户端Socket文件描述符)
  7. 客户端write写入,服务read读取
  8. 客户端断开连接时,调用close后,服务端就收到了EOF,等待服务端处理完数据也调用close

双方通信就往这个成功建立连接的Socket文件描述符中写入读取数据。

针对UDP协议通信的Socket编程模型

image.png

  1. 两个主机创建Socket,绑定端口和ip
  2. 不需要建立连接,listen、accept、connect步骤都不需要。
  3. 直接通过sendto()和recvfrom()接发数据即可

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

    本地Socket不必要绑定Ip和端口号,只需要绑定一个本地文件即可。

参考文档

小林-《图解系统》