进程间的通信方式
管道
linux命令中的" | " 就是一个管道,意思是将一个命令的输出作为另一个命令的输入,这种管道的方式很常见
进程间也可以通过管道的方式来进行通信
匿名管道
匿名管道用于有亲缘关系的进程之间进行通信
一个匿名管道有两个描述符:读取端描述符和写入端描述符,这个匿名管道是特殊的文件,只存在于内存,不存于文件系统中,即管道就是内核里面的一串缓存。使用管道是基于字节流进行通信,并且由于是缓存,大小受限,不适合进程间频繁地交换数据。
两个毫无关系的进程之间无法找到同一个管道进行通信,而子进程会复制父进程的这两个描述符,从而实现与父进程的通信,也就是进程间通信,然而,如果父、子进程都可以写入或读取,会造成混乱,因此,一般两个进程会分别关闭一个描述符,最终实现进程间的稳定通信,这也导致如果需要双向通信,需要两个管道
同理,兄弟进程的描述符都来自父进程,它们也可以利用匿名管道进行通信
命名管道
命名管道的通信原理与匿名管道类似,只不过命名管道,提前创建了一个类型为管道的设备文件,在进程里只要使用这个设备文件,就可以相互通信。
消息队列
管道的通信方式可以认为是一种同步的通信方式,效率较低。消息队列可以解决这个问题,因为它可以实现一定程度的异步。
并且消息队列是保存在内核中的消息链表,用户可以自定义消息体的数据类型(只要双方约定好),所以每个消息体都是固定大小的存储块,不像管道是无格式的字节流数据。如果进程从消息队列中读取了消息体,内核就会把这个消息体删除。
共享内存
消息队列的读取和写入的过程,都会有发生用户态与内核态之间的消息拷贝过程。共享内存的机制,就是拿出一块虚拟地址空间来,映射到相同的物理内存中。这样这个进程写入的东西,另外一个进程马上就能看到了,不需要进行拷贝和传递,大大提高了进程间通信的速度。
信号量
共享内存存在并发修改的问题:如果多个进程同时修改同一个共享内存,很有可能就冲突了。例如两个进程都同时写一个地址,那先写的那个进程会发现内容被别人覆盖了。为了防止多进程竞争共享资源,而造成的数据错乱,所以需要保护机制,使得共享的资源,在任意时刻只能被一个进程访问。正好,信号量就实现了这一保护机制。信号量其实是一个整型的计数器,主要用于实现进程间的互斥与同步,而不是用于缓存进程间通信的数据。
信号
在 Linux 操作系统中, 为了响应各种各样的事件,提供了几十种信号,分别代表不同的意义。
信号是一种异步通信方式,它可以在任何时候发送给运行中的进程,随后进程会根据信号类型进行后续操作,执行默认操作、捕捉信号执行handler或忽略信号
Socket
套接字主要用于在客户端和服务器之间通过网络进行通信。套接字是支持 TCP/IP 的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。