为Linux应用程序的开发人员,对Linux的进程间通信方式肯定是了如指掌,平时的开发中应该会大量的使用到。当你迅速的在键盘上按下【CTRL+C】终止掉一个正在运行中的命令时,你有没有仔细的思考过背后的原理呢?或者是他们是通过什么通信方式呢?这个通信方式是怎样实现的呢?本文就带着大家去Linux进程间通信一探究竟,找出他们的原理。

概念

我们都知道,应用程序在运行起来之后(进程),是相互独立的,都有自己的进程地址空间。但是往往在一些业务上需要进程间的通信,来完成系统的某个完整的功能。我们来看下进程间通信能干那些事情?首先当然最重要的是:

  1. 数据传输。一个进程需要发送数据到另一个进程,这种需求肯定是存在的。
  2. 共享数据。如果有多个进程想要访问数据,一个进程修改了内容,另一个进程能够立即看到内容变化。
  3. 资源保护:上面的的操作中存在竞争情况,内核需要提供锁和同步机制。
  4. 通知:一个进程需要向另一个进程发送消息,通知发生了某个事件。
  5. 控制:有些进程需要控制另一个进程的运行。典型的例子就是gdb,可参考之前文章【gdb到底是怎么实现的?】

通信方式

进程间的通信方式一般可以分为八种,如下:

八种通信方式

他们在不同的标准都有不同的实现,如下图所示:

通信方式框图

我们先从管道开始讲起来吧。

管道

这里说的管理特指的是无名管道,它是一种半双工的通信方式。也就是说数据只能单向流动,一般是在具有亲缘关系的进程间使用,比如父子进程。当一个进程创建了一个管道,并调用fork创建自己的一个子进程后,父进程关闭读管道端,子进程关闭写管道端,这样提供了两个进程之间数据流动的一种方式。

管道是怎么通信的呢?

首先管道是内核的一个缓冲区,而且是在内存中。管道一头连接着一个进程的输出,另一头连接着另一个进程的输入。一个缓冲区不需要很大,它被设计成为环形的数据结构,以便管道可以被循环利用。当管道中没有信息的话,从管道中读取的进程会等待,直到另一端的进程放入信息。当管道被放满信息的时候,尝试放入信息的进程会等待,直到另一端的进程取出信息。当两个进程都终结的时候,管道也自动消失。看下图:

那管道怎样建立的呢?

从原理上,管道利用fork机制建立,从而让两个进程可以连接到同一个PIPE上。最开始的时候,上面的两个箭头都连接在同一个进程1上(连接在进程1上的两个箭头),如下图。当fork复制进程的时候,会将这两个连接也复制到新的进程(进程2)。随后,每个进程关闭自己不需要的一个连接 (两个黑色的箭头被关闭; 进程1关闭从PIPE来的输入连接,进程2关闭输出到PIPE的连接),这样,剩下的红色连接就构成了如上图的PIPE。

管道在内核中具体怎么实现的呢?

在Linux内核中,并没有针对管道新增数据结构。而是巧妙的借用了文件系统的file结构和虚拟文件系统的索引节点inode。通过将两个 file 结构指向同一个临时的 VFS 索引节点,而这个 VFS 索引节点又指向一个物理页面而实现的。

具体实现

管道的实现其实也不难,源代码在内核工程中的fs/pipe.c,我们着重的讲两个比较重要的接口吧,也就是常用的pipe_read()和pipe_write(),前者是管道读函数,后者是管道写函数。

管道写函数将字节数据复制到虚拟文件系统索引节点指向的物理内存页,而读函数则是相反:读出数据。当然这里存在着竞争的管理,需要一定的同步机制,使用锁,等待队列和信号。

当我们写的时候,调用write(),内核根据传入的文件描述符fd,找到该文件的file结构。然后执行结构中f_op中的写函数。写函数在向内存写入数据之前,必须首先检查虚拟文件系统索引节点信息,检查是否有足够的内存空间可以写和内存没有被读程序锁定这两个条件,只有满足了,才真正的进行内存拷贝。

接下来写函数就会锁定内存,然后复制数据到内存,否则就在虚拟文件系统inode的等待队列中。

管道的读取过程和写入过程类似。但是,进程可以在没有数据或内存被锁定时立即返回错误信息,而不是阻塞该进程,这依赖于文件或管道的打开模式。反之,进程可以休眠在索引节点的等待队列中等待写入进程写入数据。当所有的进程完成了管道操作之后,管道的索引节点被丢弃,而共享数据页也被释放。

总结

由于篇幅的限制,八大进程间通信只讲了管道,文章开头的疑问也只能等到后续文章了,也算是留个悬念吧。

图解Linux进程间通信实现原理(1)的更多相关文章

  1. Linux进程间通信(五):信号量 semget()、semop()、semctl()

    这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信 -- 信号.下面 ...

  2. Linux进程间通信——使用信号量

    这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信——使用信号.下面 ...

  3. c/c++ linux 进程间通信系列5,使用信号量

    linux 进程间通信系列5,使用信号量 信号量的工作原理: 由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的: P(sv):如果sv的值大于零,就给它减1:如果 ...

  4. Linux进程间通信--使用信号量【转】

    本文转载自:http://blog.csdn.net/ljianhui/article/details/10243617 这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号 ...

  5. Linux进程间通信——使用信号量(转)

    这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信——使用信号.下面 ...

  6. Linux进程间通信—管道

    Linux下的进程通信手段基本上是从UNIX平台上的进程通信手段继承而来的.而对UNIX发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间 ...

  7. Linux进程间通信——使用信号量【转】

    本文转载自:http://blog.csdn.net/ljianhui/article/details/10243617 这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号 ...

  8. [转载]Linux Bond的原理及其不足

    本文转自http://www.yunweipai.com/archives/1969.html 支持原创.尊重原创,分享知识! 在企业及电信Linux服务器环境上,网络配置都会使用Bonding技术做 ...

  9. Linux进程间通信(一): 信号 signal()、sigaction()

    一.什么是信号 用过Windows的我们都知道,当我们无法正常结束一个程序时,可以用任务管理器强制结束这个进程,但这其实是怎么实现的呢?同样的功能在Linux上是通过生成信号和捕获信号来实现的,运行中 ...

随机推荐

  1. [APB VNext 笔记] UI

    一直想给我做的服务写UI.但苦于现在ABPVNext框架对SPA支持不好.只好先放弃VUE.先弄个UI在说.ABPVNext中的框架都是用Helper封装好的Label.不知道怎么使用,于是翻源代码. ...

  2. jQuery入门简述

    jQuery 是一套快速的,简洁的 javaScript 脚本库,jQuery 由美国人 John Resig 创建,至今已吸引了来自世界各地的众多 javaScript 高手加入其组织,使用户能更方 ...

  3. 脱壳系列—— *加密脱壳(Android使用手册破解)

    作者:i春秋作家HAI_ZHU 0×00 前言 好久没有写文了,要好好开动一下了.很多事情要忙.这篇文章本来很早之前就要写的,但是因为很多事情就拖了很久. 前置内容 HAI_使用手册 知识总结 0×0 ...

  4. Go map使用

    前言 map 是在 Go 中将值(value)与键(key)关联的内置类型.通过相应的键可以获取到值. 在一个map里所有的键都是唯一的,而且必须是支持==和!=操作符的类型,切片.函数以及包含切片的 ...

  5. Oracle学习笔记——Linux下开启Oracle

    1.开启数据库 sqlplus  /  as sysdba startup 2.启动监听:lsnrctl  start; 查看监听状态:lsnrctl status; 3.登入数据库 Linux 设置 ...

  6. dubbo线程池作用于接口而不是方法

    记一次线上dubbo服务超时和线程池满问题排查 可能调用的接口没问题,但是该服务中的其他接口占用完了线程池,导致调用超时被拒绝处理.

  7. 【Hibernate】检索方式

    一.概述 二.HQL 2.1 简介 2.2 查询所有记录 2.3 查询使用别名 2.4 排序 2.5 分页查询 2.6 单个对象查询 2.7 参数绑定 2.8 投影操作 2.9 模糊查询 2.10 S ...

  8. script标签中的async、defer属性

    Script标签是我们常用的引用js脚本的一种方式. 撸代码的时候,我们常常只写src属性,直接忽略其他属性. 最近发现了2个可以利用的属性:async.defer. 顾名思义async就是异步,在不 ...

  9. .NET 推荐博客

    燎原之星的博客 农码一生博文索引 http://www.cnblogs.com/zhaopei/p/Indexes.html 那些年搞不懂的术语.概念:协变.逆变.不变体 http://www.cnb ...

  10. element 中表单验证的解析。

    https://blog.csdn.net/qq_24504591/article/details/88048894 https://segmentfault.com/a/11900000125513 ...