共享内存,管道,socket等进程间通信方式的优缺点

进程间通信的方式有很多,常见的有信号,信号量,消息队列,管道,共享内存,和socket等,这里我们主要讨论管道,共享内存,和socket,其他的比较简单只做简单的介绍。

一 信号

    信号主要用于通知某个进程发生了什么事,就像你打电话通知某个人某件事一样,事先注册号信号相应的注册函数就可以了。

二 信号量

    信号量实际上是一个计数器,通常在多线程或者多进程开发中会用到,主要用来控制多线程多进程对于共享资源访问,通常配合锁来实现同时只有一个进程或者线程操作共享资源,防止数据的不同步。

三 消息队列

    消息队列是消息的链表,存放在内核中并由消息队列表示符,我们可以在两个进程之间通过消息队列来实现进程间通信。不过消息队列在工作中好像并不怎么常用。

接下来主要谈谈剩下的三种,这些是我们经常会用到的。

四 管道

    管道分为有名管道和无名管道两种

    1 无名管道 ,主要用于父进程与子进程之间,或者两个兄弟进程之间。在linux系统中可以通过系统调用建立起一个单向的通信管道,且这种关系只能由父进程来建立。因此,每个管道都是单向的,当需要双向通信时就需要建立起两个管道。管道两端的进程均将该管道看做一个文件,一个进程负责往管道中写内容,而另一个从管道中读取。这种传输遵循“先入先出”(FIFO)的规则。

    2 有名管道,命名管道是为了解决无名管道只能用于近亲进程之间通信的缺陷而设计的。命名管道是建立在实际的磁盘介质或文件系统(而不是只存在于内存中)上有自己名字的文件,任何进程可以在任何时间通过文件名或路径名与该文件建立联系。为了实现命名管道,引入了一种新的文件类型——FIFO文件(遵循先进先出的原则)。实现一个命名管道实际上就是实现一个FIFO文件。命名管道一旦建立,之后它的读、写以及关闭操作都与普通管道完全相同。虽然FIFO文件的inode节点在磁盘上,但是仅是一个节点而已,文件的数据还是存在于内存缓冲页面中,和普通管道相同。

    管道有很多致命的缺点,比如只能在具有亲缘关系的进程间通信,只能单向传输数据,另外管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小,管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,最后就是管道操作不当很容易阻塞。因此管道虽然偶尔会见到,但是很少人会用。

五 共享内存

     要使用一块共享内存,进程必须首先分配它。随后需要访问这个共享内存块的每一个进程都必须将这个共享内存绑定到自己的地址空间中。当完成通信之后,所有进程都将脱离共享内存,并且由一个进程释放该共享内存块。理解 Linux 系统内存模型可以有助于解释这个绑定的过程。在 Linux 系统中,每个进程的虚拟内存是被分为许多页面的。这些内存页面中包含了实际的数据。每个进程都会维护一个从内存地址到虚拟内存页面之间的映射关系。尽管每个进程都有自己的内存地址,不同的进程可以同时将同一个内存页面映射到自己的地址空间中,从而达到共享内存的目的。分配一个新的共享内存块会创建新的内存页面。因为所有进程都希望共享对同一块内存的访问,只应由一个进程创建一块新的共享内存。再次分配一块已经存在的内存块不会创建新的页面,而只是会返回一个标识该内存块的标识符。一个进程如需使用这个共享内存块,则首先需要将它绑定到自己的地址空间中。这样会创建一个从进程本身虚拟地址到共享页面的映射关系。当对共享内存的使用结束之后,这个映射关系将被删除。当再也没有进程需要使用这个共享内存块的时候,必须有一个(且只能是一个)进程负责释放这个被共享的内存页面。

    这个是经常用的,共享内存号称是最快的进程间通信方式,她在系统内存中开辟一块内存区,分别映射到各个进程的虚拟地址空间中,任何一个进程操作了内存区都会反映到其他进程中,各个进程之间的通信并没有像copy数据一样从内核到用户,再从用户到内核的拷贝。这种方式可以像访问自己的私有空间一样访问共享内存区,但是这事这种特性加大了共享内存的编程难度,对于数据的同步问题是一个难点,没有一定的经验很 容易造成数据的混乱。但是我们可以使用一个折中的方法,我们可以结合它和管道来使用。

    举个例子进程A和B通信,如果我们用一块共享内存区来实现它们的通信,对于数据的同步是个令人头疼的问题,但是我们可以用两个共享内存区。大笑

内存区 1 ,A->B,A只能写数据,B只能读数据

内存区 2, B->A,A只能读数据,B只能写数据

    这样就不会因为,多个进程同时鞋一块内存造成数据的混乱了,看起来是不是有点像管道,其实就是管道的机制,但是不同的是,她的速度要比管道快的多,他的数据大小没有限制(当然不能超过系统的内存大小),当然也不会有阻塞问题。但是这种方式也有明显的缺点,它只适合点对点的通信,如果要多个进程间通信,内存区的数量会呈线性增长,会造成数据的冗余,并且管理起来也会变得困难,如果你的进程数量在各位数着中方式是一个好的选择,否则就要采用一块共享内存,同时做好数据的同步了。(对于这种模式我写了一个小的domo供大家参考:博客:点击打开链接,github:点击打开链接)

最后一点,通过名字就知道它是基于内存的,所以他只能在同一主机上使用,如果我们要做分布式应用或者跨物理机通信,那么socket就是我们唯一的选择了。

六 socket

    socket是一种面相网络的一种进程间通信方式,只要有网络存在,它可以跨越任何限制。socket编程是一个宽泛的说法,对于我们程序猿来说tcp,udp,http是我们经常用的一些网络协议。当然socket也是我们用的最多的,他的限制住要在与带宽,网络延时和连接数量的限制等。这也是我们在开发服务程序时都要面对c10k问题的原因。

下面看一段别人对于使用这些方式的前提的看法:(来源:http://blog.csdn.net/fengye245/article/details/7783717)

1. 联网的还是非联网的.IPC适用于单台主机上的进程或线程间的.如果应用程序有可能分布到多台主机上,那就要考虑使用套接字代替IPC,从而简化以后向联网的应用程序转移的工作. 
2. 可移植性. 
3. 性能,在具体的开发环境下运行测试程序,比较几种IPC的性能差异. 
4. 实时调度.如果需要这一特性,而且所用的系统也支持posix实时调度选项,那就考虑使用Posix的消息传递和同步函数. 

 

 

  • 15
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是几种常见的客户端和服务器之间通信的协议和技术,以及它们的优缺点: 1. 消息队列(Message Queue):消息队列是一种异步通信方式,它允许发送者向队列中发送消息,接收者从队列中读取消息。消息队列可以采用多种实现方式,例如 RabbitMQ、Apache ActiveMQ、ZeroMQ 等。消息队列的优点是: - 异步通信:发送者和接收者之间的通信是异步的,发送者不需要等待接收者的回应就可以继续执行。 - 可靠性:消息队列通常提供持久化存储机制,可以保证消息不会丢失。 - 扩展性:消息队列可以支持多个生产者和多个消费者,并且可以在不影响其他组件的情况下进行扩展。 消息队列的缺点是: - 实现复杂:由于消息队列需要保证可靠性和扩展性,所以实现起来比较复杂。 - 性能瓶颈:当消息队列中的消息数量增多时,可能会出现性能瓶颈。 2. 共享内存(Shared Memory):共享内存是一种通过将内存区域映射到多个进程的地址空间来实现进程间通信方式共享内存的优点是: - 高效性:由于共享内存直接在内存中进行数据传输,所以效率非常高。 - 简单性:共享内存相对于其他通信方式来说,实现起来比较简单。 共享内存的缺点是: - 数据同步:由于多个进程可以同时访问共享内存,因此需要考虑数据同步的问题,否则可能会出现数据一致性问题。 - 安全性:共享内存需要考虑进程之间的权限问题,否则可能会导致安全性问题。 3. 进程间管道(Pipe):进程间管道是一种半双工的通信方式,它允许进程间进行双向通信,但是只能在父进程和子进程之间使用。进程间管道的优点是: - 简单性:进程间管道相对于其他通信方式来说,实现起来比较简单。 - 可靠性:进程间管道可以保证数据传输的可靠性。 进程间管道的缺点是: - 限制性:进程间管道只能在父进程和子进程之间使用,不支持其他进程之间的通信。 - 数据量限制:由于管道是基于缓存区的,所以数据量有限制。 4. SocketSocket 是一种网络编程的 API

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值