进程间通信的历史与未来

- START -

我们都知道线程是共享内存空间的,因此不会发生所谓的通信,而进程则存在如何防止多进程同时访问数据的排他控制问题。

5 种进程间通信的方式

  • 管 道
  • SysV IPC
  • TCP 套接字
  • UDP 套接字
  • UNIX 套接字

管道

  所谓管道,就是能够从一侧输入,然后从另一侧读取的文件描述符对。Shell 中的管道也是通过这一方式实现的。

  文件描述符在每个进程中是独立存在的,但创建子进程时会继承父进程中所有的文件描述符,因此它可以用于在具有父子、兄弟关系的进程之间进行通信。

  例如,在具有父子关系的进程之间进行管道通信时,可以按下列步骤操作。在这里为了简单期间,我们只由子进程向父进程进行通信。

  1. 首先,使用 pipe 系统调用,创建一对文件描述符。下面我们将读取一方的文件描述符称为 r,将写入一侧的文件描述符称为 w
  2. 通过 fork 系统调用创建子进程。
  3. 在父进程一方将描述符 w 关闭。
  4. 在子进程一方将描述符 r 关闭。
  5. 在子进程一方将要发送给父进程的数据写入描述符 w
  6. 在父进程一方从描述符 r 中读取数据。

笔者直接上代码演示:

#!/usr/bin/env python
#coding:utf8
import multiprocessing
import time

def process_one(pipe):
    while True:        
        for i in range(3):            
        print "Process-one send: {0}".format(i)
            pipe.send(i)
            time.sleep(1)

def process_two(pipe):
    while True:        
        print "Process-two received: {0}".format(pipe.recv())
        time.sleep(1)
        
# 创建一个管道
pipe = multiprocessing.Pipe()
# pipe 对象:
# (<read-write Connection, handle 5>, <read-write Connection, handle 6>)


p1 = multiprocessing.Process(target=process_one, args=(pipe[0],))
p2 = multiprocessing.Process(target=process_two, args=(pipe[1],))

# 开始子进程
p1.start()
p2.start()

# 等待,直到子进程结束
p1.join()
p2.join()

结果

Process-one send: 0
Process-two received: 0
Process-one send: 1
Process-two received: 1
Process-one send: 2
Process-two received: 2
Process-one send: 0
Process-two received: 0
Process-one send: 1
Process-two received: 1
Process-one send: 2
Process-two received: 2
...

SysV IPC

  UNIX 的 System V (Five) 版本引入了一组称为 SysV IPC 的进程间通信 API,其中 IPC 就是 Inter Process Communication (进程间通信)的缩写。

SysV IPC 包括下列 3 种通信方式。

  • 消息队列
  • 信号量
  • 共享内存

  消息队列是一种用于进程间通信的手段。管道只是一种流机制,每次写入数据的长度等信息是无法保存的,相对的,消息队列则可以保存写入消息的长度。

  信号量(semaphore)是一种带有互斥计数器的标志(flag)。这个词原本是荷兰语「旗语」的意思,在信号量中可以设定对某种「资源」同时访问数量的上限。

  共享内存是一块在进程间共享的内存空间。通过将共享内存空间分配到自身进程内存空间中(attach)的方式来访问。由于对共享内存的访问并没有进行排他控制,因此无法避免一些偶发性问题,必须使用信号量等手段进行保护。

  不过,SysV IPC 有一个资源泄露的问题:由于 SysV IPC 的通信路径能够跨进程访问,因此在使用时需要向操作系统申请分配才能进行通信,通信结束之后还必须显式的销毁,如果忘记销毁的话,就会在操作系统中留下垃圾。

管道之类的方式,则在其所属进程结束的同时会自动销毁,因此比 SysV IPC 要更加易用。

  其次,学习使用新的 API 要花一些精力,但结果也只能用在一台电脑上的进程间通信中,真的让人没什么动力去学呢。

  大家可以在 Linux 中参考一下:

# man svipc

套接字

  System V 所提供的进程间通信手段是 SysV IPC,相对的,BSD 则提供了套接字的方式。和其他进程间通信方式相比,套接字有一些优点:

  • 通信对象不仅限于同一台计算机,或者说套接字本身主要就是为了计算机之间的通信而设计的。
  • (和 SysV IPC 不同)套接字也是一种文件描述符,可进行一般的输入输出。尤其是可以使用 select 系统调用,在通常 I/O 的同时进行「等待」,这一点非常方便。
  • 套接字在进程结束后会由操作系统自动释放,因此无需担心资源泄漏的问题。
  • 套接字(由于其优秀的设计)从很早开始就被吸收进 System V 等系统了,因此在可移植性方面的顾虑较少。

  现在网络几乎完全依赖于套接字。各位所使用的几乎所有的服务的通信都是基于套接字实现的,这样说应该没什么大问题。

套接字分很多种,其中具有代表性的包括:

  • TCP 套接字
  • UDP 套接字
  • UNIX 套接字

  TCP(Transmission Control Protocol,传输控制协议)套接字和 UDP(User Datagram Protocol,用户数据协议)套接字都是建立在 IP(Internet Protocol,网际协议)协议之上的上层网络通信套接字。这两种套接字都可用于以网络为媒介的结算机通信。但它们在性质上有一些区别。

  TCP 套接字是一种基于连接的、具备可靠性的数据流通信套接字。所谓基本连接,是指通信的双方是固定的;而所谓具备可靠性,是指能够侦测数据发送成功或是失败(出错)的状态。

  所谓数据流通信,是指发送的数据是作为字节流来处理的,和通常的输入输出一样,不会保存写入的数据长度信息。

  看了上面的内容,大家可能觉得这些都是理所当然的。我们和 UDP 套接字对比一下,就能够理解其中的区别了。

  UDP 套接字和 TCP 套接字相反,是一种能够无需连接进行通信、但不具备可靠性的数据通信套接字。所谓能够无需连接进行通信,是指无需固定连接到指定对象,可以直接发送数据;不具备可靠性是指可能会出现中途由于网络状况等因素导致发送数据丢失的情况。

  在数据通信中,发送的数据再原则上是能够保存其长度的。但是,在数据过长等情况下,发送的数据可能会被分割。

  先不说无连接通信这一点,UDP 和其他一些性质可能会让大家感到非常难用。这是因为 UDP 几乎是原原本本直接使用了作为其基础的 IP 协议。相反 TCP 为了维持可靠性,在 IP 协议之上构建了各种机制。UDP 的特点是结构简单,对系统产生的负荷也较小。

  因此,在语音通信(如 IP 电话等)中一般使用 UDP,因为通信的性能比数据传输的可靠性要更加重要,也就是说,相比通话中包含少许杂音来说,还是保证较小的通话延迟要更加重要。

  TCP 套接字和 UDP 套接字都是通过 IP 地址和端口号来进行工作的。例如,http 协议中的 http://www.google.com:80/ 就表示与 www.google.com (IP 地址为:31.13.71.7)所代表的计算机的 80 端口建立连接.

UNIX 套接字

  同样是套接字,UNIX 套接字和 TCP、UDP 套接字相比,可以算是一个异类。基于 IP 的套接字一般是通过主机名端口号来识别通信对象的,而 UNIX 套接字则是在 UNIX 文件系统上创建一个特殊文件,并用该文件的路径进行识别。由于这种方式使用的是文件系统,因此大家可以看出,UNIX 套接字只能用于同一台计算机上的进程间通信。

  UNIX 套接字并不是基于 IP 的套接字,它可用于向一台计算机上其他进程提供服务的某种服务程序。

最后

  在进程通信手段中,套接字算是非常好用的,但是即便如此,在考虑对工作进行「委派」时,其易用性还并不理想。套接字本来是为网络服务器的实现而设计的,但作为构建分布式应用程序的手段来说,还是太原始了。

MQ(Message Queue,消息队列)就是为了解决这个问题而诞生的,RPC(Remote Procedure Call,远程过程调用)呢,这一切有没有联系呢?希望本文可以引发你的思考

原文发布于微信公众号 - 随心DevOps(heart-devops)

原文发表时间:2017-12-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Ceph对象存储方案

Luminous版本PG 分布调优

Luminous版本开始新增的balancer模块在PG分布优化方面效果非常明显,操作也非常简便,强烈推荐各位在集群上线之前进行这一操作,能够极大的提升整个集群...

3265
来自专栏我和未来有约会

Kit 3D 更新

Kit3D is a 3D graphics engine written for Microsoft Silverlight. Kit3D was inita...

2636
来自专栏杨龙飞前端

scrollto 到指定位置

2564
来自专栏张善友的专栏

LINQ via C# 系列文章

LINQ via C# Recently I am giving a series of talk on LINQ. the name “LINQ via C...

2675
来自专栏转载gongluck的CSDN博客

cocos2dx 打灰机

#include "GamePlane.h" #include "PlaneSprite.h" #include "BulletNode.h" #include...

5686
来自专栏一个会写诗的程序员的博客

Spring Reactor 项目核心库Reactor Core

Non-Blocking Reactive Streams Foundation for the JVM both implementing a Reactiv...

2242
来自专栏张善友的专栏

Silverlight + Model-View-ViewModel (MVVM)

     早在2005年,John Gossman写了一篇关于Model-View-ViewModel模式的博文,这种模式被他所在的微软的项目组用来创建Expr...

3038
来自专栏落花落雨不落叶

canvas画简单电路图

66111
来自专栏C#

DotNet加密方式解析--非对称加密

    新年新气象,也希望新年可以挣大钱。不管今年年底会不会跟去年一样,满怀抱负却又壮志未酬。(不过没事,我已为各位卜上一卦,卦象显示各位都能挣钱...)...

4988
来自专栏张善友的专栏

Mix 10 上的asp.net mvc 2的相关Session

Beyond File | New Company: From Cheesy Sample to Social Platform Scott Hansel...

2627

扫码关注云+社区