面试官问:“请你说说进程间的通信方式有哪些?”
我:“啊,进程间通信,额,额,额”
进程间通信的方式
- 管道
- 消息队列
- 共享内存
- 信号量
- 信号
- Socket
管道
管道就是Linux命令中的gaoxi@DESKTOP-298U6LA:~$ ps -ef | grep java
gaoxi 71 9 0 20:09 tty1 00:00:00 grep --color=auto java
|
管道符。其左右就是将前面一条命令的结果作为下一条命令的入参。这里这种管道符具体来说叫做匿名管道符。命名管道符
命名管道符又称FIFO。可以通过mkfifo命令来创建并指定管道的名字
此时向管道中编辑内容,控制台会卡住等待接收
可以通过cat < 管道名称的方式取出管道中的内容
消息队列
消息队列这种方式的具体如何使用小林并没有给出具体的用法。这里我提取中几个重点的介绍
- 消息队列通信过程中,存在内核态与用户态之间的数据拷贝开销
共享内存
共享内存的方式顾名思义,就是两个进程都可以操作的一块物理内存。我们知道,每个进程都是使用自己的虚拟内存。虚拟内存最终映射到具体的物理内存。进程A和进程B在没有沟通必要的时候,各自的虚拟内存映射的物理内存是不同的。那么若想存在共享内存的话,就必须将进程A和进程B的某一块虚拟内存映射到相同的一块物理内存上。这样进程A对这块内存的读写对于进程B也是可见的。这就完成了进程间的通信。
信号量
小林说:“信号量其实就是一个整型的计数器”。
两个主要的操作:
P:信号量-1,如果P操作后信号量小于0 阻塞
V:信号量+1,若V操作后信号量 <= 0 唤醒阻塞进程
特殊的信号量
信号量为1:互斥信号量
信号量为0:同步信号量,就是两个线程V线程走完,P线程走
信号
信号用于异常情况下的通信。Linux提供了几十种信号,可以通过kill -l
的方式查看
CTRL+C:对应图中2
CTRL+Z:对应图中20
信号是进程间通信机制中唯一的异步通信机制,用户进程对于这些信号的处理方式有以下几种:
- 执行默认操作:每个信号需要执行什么操作都是固定好的
- 捕捉信号:可以信号发生时,执行对应自定义函数(进程中的)
- 忽略信号:可以忽略信号,但是9和SEGSTOP不可忽略
Socket
Socket主要用于两个不同主机间的进程进行通信,但是同一个主机的两个进程也可以通过Socket通信,但是这就好像,面对面坐的两个人,在用手机打电话。额,形象的比喻。针对TCP协议通信的Socket编程模型
这里全用小林的图了,小林 yyds好吧
- 服务端初始化Socket,得到文件描述符(万物皆文件)
- 服务端调用bind,将主机的ip和端口绑定
- 服务端调用listen,进行监听
- 服务端调用accept,等待客户端连接
- 客户端初始化socket,并调用connect想服务端请求
- 服务端accept返回用于传输的socket文件描述符(服务端返回给客户端Socket文件描述符)
- 客户端write写入,服务read读取
- 客户端断开连接时,调用close后,服务端就收到了EOF,等待服务端处理完数据也调用close
双方通信就往这个成功建立连接的Socket文件描述符中写入读取数据。
针对UDP协议通信的Socket编程模型
- 两个主机创建Socket,绑定端口和ip
- 不需要建立连接,listen、accept、connect步骤都不需要。
- 直接通过sendto()和recvfrom()接发数据即可
针对本地进程间通信的 socket 编程模型
本地Socket不必要绑定Ip和端口号,只需要绑定一个本地文件即可。
参考文档
小林-《图解系统》