1.管道
Linux上的管道分两种类型:
- 匿名管道
- 命名管道
我们可以把匿名管道和命名管道分别叫做PIPE和FIFO,这两种管道也叫做有名或无名管道。匿名管道最常见的形态就是我们在shell操作中最常用的”|”。它的特点是只能在父子进程中使用,父进程在产生子进程前必须打开一个管道文件,然后fork产生子进程,这样子进程通过拷贝父进程的进程地址空间获得同一个管道文件的描述符,以达到使用同一个管道通信的目的。此时除了父子进程外,没人知道这个管道文件的描述符,所以通过这个管道中的信息无法传递给其他进程。这保证了传输数据的安全性,当然也降低了管道了通用性,于是系统还提供了命名管道。
![](https://img2020.cnblogs.com/blog/818047/202009/818047-20200908102205372-1838766719.png)
1.1 匿名管道
如上图中描述,fork产生的子进程会继承父进程对应的文件描述符。利用这个特性,父进程先pipe创建管道之后,子进程也会得到同一个管道的读写文件描述符。从而实现了父子两个进程使用一个管道可以完成半双工通信。此时,父进程可以通过fd[1]给子进程发消息,子进程通过fd[0]读。子进程也可以通过fd[1]给父进程发消息,父进程用fd[0]读。管道推荐的使用方法是其单工模式:即只有两个进程通信,一个进程只写管道,另一个进程只读管道。
![](https://img2020.cnblogs.com/blog/818047/202009/818047-20200908102326138-1654057790.png)
此时两个进程就只用管道实现了一个单工通信,并且这种状态下不用考虑多个进程同时对管道写产生的数据交叉的问题,这是最经典的管道打开方式,也是我们推荐的管道使用方式。
1.2 命名管道
2.消息队列
消息队列,就是一个消息的链表,是一系列保存在内核中消息的列表。用户进程可以向消息队列添加消息,也可以向消息队列读取消息。
消息队列与管道通信相比,其优势是对每个消息指定特定的消息类型,接收的时候不需要按照队列次序,而是可以根据自定义条件接收特定类型的消息。
可以把消息看做一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息,对消息队列有读权限的进程可以从消息队列中读取消息
- 匿名管道是跟随进程的,消息队列是跟随内核的,也就是说进程结束之后,匿名管道就死了,但是消息队列还会存在(除非显示调用函数销毁)
- 管道是数据流式存取,消息队列是数据块式存取
3.共享内存
共享内存允许两个或更多进程访问同一块内存。当一个进程改变了这块地址中的内容的时候,其它进程都会察觉到这个更改。
4.信号量
5.信号
6.socket
socket是"打开—读/写—关闭"模式的实现,以使用TCP协议通讯的socket为例,其交互流程大概是这样子的:
服务器根据地址类型(ipv4,ipv6)、socket类型、协议创建socket
服务器为socket绑定ip地址和端口号
服务器socket监听端口号请求,随时准备接收客户端发来的连接,这时候服务器的socket并没有被打开
客户端创建socket
客户端打开socket,根据服务器ip地址和端口号试图连接服务器socket
服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这时候socket进入阻塞状态,所谓阻塞即accept()方法一直到客户端返回连接信息后才返回,开始接收下一个客户端谅解请求
客户端连接成功,向服务器发送连接状态信息
服务器accept方法返回,连接成功
客户端向socket写入信息
服务器读取信息
客户端关闭
服务器端关闭