看了那么多博客,大致进程的通信方式可以分为下面几种:1.管道(匿名管道pipe和命名管道FIFO),2.信号,3.信号量,4.共享内存,5.消息队列,6.套接字,7.文件
谈谈进程间通信的几种方式?这篇博客说的非常清晰
进程间通讯的7种方式 简约版也很详细
进程间的六种通信
匿名管道PIPE
在内核中申请一块固定大小的缓冲区,程序拥有写入和读取的权利,一般使用fork函数实现父子进程的通信
命名管道FIFO
在内核中申请一块固定大小的缓冲区,程序拥有写入和读取的权利,没有血缘关系的进程也可以进程间通信。
上一种进程间通信的方式是匿名的,所以只能用于具有亲缘关系的进程间通信,命名管道的出现正好解决了这个问题。FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存储文件系统中。命名管道是一个设备文件,因此即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO相互通信。
管道通信的特点:1,面向字节流,2,生命周期随内核,3,自带同步互斥机制。4,半双工,单向通信,两个管道实现双向通信。
信号
信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。
进程可以通过三种方式来响应一个信号:(1)忽略信号,即对信号不做任何处理,其中,有两个信号不能忽略:SIGKILL及SIGSTOP;(2)捕捉信号。定义信号处理函数,当信号发生时,执行相应的处理函数;(3)执行缺省操作,Linux对每种信号都规定了默认操作。
Linux主要有两个函数实现信号的安装:signal()、sigaction()。其中signal()在可靠信号系统调用的基础上实现, 是库函数。
信号是进程间通信机制中唯一的异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发生了。信号机制经过POSIX实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息。
对于一个完整的信号生命周期(从信号发送到相应的处理函数执行完毕)来说,可以分为三个重要的阶段,这三个阶段由四个重要事件来刻画:信号诞生;信号在进程中注册完毕;信号在进程中的注销完毕;信号处理函数执行完毕
信号量PV操作
在内核中创建一个信号量集合(本质是个数组),数组的元素(信号量)都是1,使用P操作进行-1,使用V操作+1,
(1) P(sv):如果sv的值⼤大于零,就给它减1;如果它的值为零,就挂起该进程的执⾏ 。
(2) V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运⾏,如果没有进程因等待sv⽽挂起,就给它加1。
PV操作用于同一进程,实现互斥。
PV操作用于不同进程,实现同步。
2,功能:
对临界资源进行保护。
消息队列
在内核中创建一队列,队列中每个元素是一个数据报,不同的进程可以通过句柄去访问这个队列。消息队列提供了⼀个从⼀个进程向另外⼀个进程发送⼀块数据的⽅法。每个数据块都被认为是有⼀个类型,接收者进程接收的数据块可以有不同的类型值
消息队列也有管道⼀样的不⾜,就是每个消息的最⼤⻓度是有上限的(MSGMAX),
每个消息队 列的总的字节数是有上限的(MSGMNB),系统上消息队列的总数也有⼀个上限(MSGMNI)
特点:
1, 消息队列可以认为是一个全局的一个链表,链表节点钟存放着数据报的类型和内容,有消息队列的标识符进行标记。
2,消息队列允许一个或多个进程写入或者读取消息。
3,消息队列的生命周期随内核。
4,消息队列可实现双向通信。
共享内存
1,概念:
将同一块物理内存一块映射到不同的进程的虚拟地址空间中,实现不同进程间对同一资源的共享。
共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。
2,特点:
1,不用从用户态到内核态的频繁切换和拷贝数据,直接从内存中读取就可以。
2,共享内存是临界资源,所以需要操作时必须要保证原子性。使用信号量或者互斥锁都可以。
3,生命周期随内核
为什仫共享内存的方式比其他进程间通信的方式效率高?
消息队列,FIFO,管道的消息传递方式一般为 :
1).服务器获取输入的信息;
2).通过管道,消息队列等写入数据至内存中,通常需要将该数据拷贝到内核中;
3).客户从内核中将数据拷贝到自己的客户端进程中;
4).然后再从进程中拷贝到输出文件;
上述过程通常要经过4次拷贝,才能完成文件的传递。
而共享内存只需要:
1).输入内容到共享内存区
2).从共享内存输出到文件
上述过程不涉及到内核的拷贝,这些进程间数据的传递就不再通过执行任何进入内核的系统调用来传递彼此的数据,节省了时间,所以共享内存是这五种进程间通信方式中效率最高的。
套接字
socket,即套接字是一种通信机制,凭借这种机制,客户/服务器(即要进行通信的进程)系统的开发工作既可以在本地单机上进行,也可以跨网络进行。也就是说它可以让不在同一台计算机但通过网络连接计算机上的进程进行通信。
套接字的属性
套接字的特性由3个属性确定,它们分别是:域、类型和协议。
1、套接字的域
它指定套接字通信中使用的网络介质,最常见的套接字域是AF_INET,它指的是Internet网络。当客户使用套接字进行跨网络的连接时,它就需要用到服务器计算机的IP地址和端口来指定一台联网机器上的某个特定服务,所以在使用socket作为通信的终点,服务器应用程序必须在开始通信之前绑定一个端口,服务器在指定的端口等待客户的连接。另一个域AF_UNIX表示UNIX文件系统,它就是文件输入/输出,而它的地址就是文件名。
2、套接字类型
因特网提供了两种通信机制:流(stream)和数据报(datagram),因而套接字的类型也就分为流套接字和数据报套接字。这里主要讲流套接字。
流套接字由类型SOCK_STREAM指定,它们是在AF_INET域中通过TCP/IP连接实现,同时也是AF_UNIX中常用的套接字类型。流套接字提供的是一个有序、可靠、双向字节流的连接,因此发送的数据可以确保不会丢失、重复或乱序到达,而且它还有一定的出错后重新发送的机制。
与流套接字相对的是由类型SOCK_DGRAM指定的数据报套接字,它不需要建立连接和维持一个连接,它们在AF_INET中通常是通过UDP/IP协议实现的。它对可以发送的数据的长度有限制,数据报作为一个单独的网络消息被传输,它可能会丢失、复制或错乱到达,UDP不是一个可靠的协议,但是它的速度比较高,因为它并一需要总是要建立和维持一个连接。
3、套接字协议
只要底层的传输机制允许不止一个协议来提供要求的套接字类型,我们就可以为套接字选择一个特定的协议。通常只需要使用默认值。