Linux进程间通信

进程间通信是什么?

两个或多个进程实现数据层面的交互

因为进程独立性的存在, 导致进程通信的成本比较高

为什么需要进程间通信

1 数据传输:一个进程需要将它的数据发送给另一个进程。
2 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
3 资源共享:多个进程之间共享同样的资源。为了做到这一点,需要内核提供互斥和同步机制。
4 进程控制:有些进程希望完全控制另一个进程的执行(如 Debug 进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

怎么实现进程间通信?

a.进程间通信的本质:必须让不同的进程看到同一份资源
b.资源其实就是特定形式的内存空间在这里插入图片描述
c.这个“资源”谁提供?
一般是操作系统提供。

为什么不是两个进程中的某个自己提供?
因为进程间具有独立性, 如果这个公共资源是由其中一个提供的, 那这个资源依然是这个进程独有的, 别人还是看不到, 所以这个空间还是得第三方来提供

d. 我们进程想访问这个空间, 本质就是访问操作系统!
进程代表的就是用户, 操作系统一般不允许用户访问自己内部的资源。

所以这个资源从创建, 到使用, 到释放, 这整个过程 – 都需要使用系统调用接口

操作系统中会有很多个进程之间需要通信, 所以会有很多这样的资源被创建, 操作系统需要管理这些资源, 所以他会对这些资源先描述再组织
在这里插入图片描述
e 通信方式

进程间通信是有标准的
ststem V(本机内部) && posix(网络)
在这里插入图片描述
POSIX
在这里插入图片描述
还有一种基于文件级的通信方式 – 管道, 他不属于上述两个标准的任意一个

管道

管道其实就是一个内存级文件

管道的原理

在这里插入图片描述

父进程先创建一个内存级文件, 这个文件内容不会刷新进磁盘, 他的file_operatiors 指向的是对该文件的缓冲区做读写的方法。 然后创建子进程后, 两个进程都指向了这个内存级文件, 当父进程对该文件的缓冲区做写入后, 子进程就可以从缓存区里读信息。

在这里插入图片描述
父进程在创建管道的时候, 会将管道既以写方式打开, 又以读方式打开。
在这里插入图片描述
然后创建子进程, 最后根据具体谁读谁写关闭不需要的文件。

上述只是一个简洁版。

管道真实是怎么做的呢?
在这里插入图片描述

我们父进程先以读方式创建一个文件

在这里插入图片描述

然后再以写方式创建一个文件, 这两个文件虽然有不同的file_struct 但是他们指向的是同一个缓冲区。

在这里插入图片描述
然后父进程创建出子进程

在这里插入图片描述
然后父子进程关闭不需要的文件

可以看出, 我们的管道其实其实是只支持单向通信

刚刚讲的都是父子进程之间, 而如果这两个进程之间没有任何的关系, 那么还能用这种方式进行通信吗?

不可以! 只有父子或者兄弟 … 这种具有血缘关系的进程才能通过这种方式通信

由于这个用于通信的管道没有inode 没有路径, 没有名字, 所以我们把这种管道称为匿名管道

讲了这么多其实我们都还没有开始通信, 我们所做的其实是在建立通信信道
为什么需要进行这么多的操作? 进程间通信是需要成本的

接口 和 代码实现

在这里插入图片描述

在这里插入图片描述
我们来解释一下这个pipefd【2】的意思,这个参数其实是输出型参数, 他会将你用两种方式打开的内存级文件的fd返回回来, 其中piped[0] 是读 piped[1]是写下标

在这里插入图片描述

我们现在试用一下这个接口
在这里插入图片描述
在这里插入图片描述
这样我们就建立好了单向信道

在这里插入图片描述
我们来验证一下子文件的写入功能
在这里插入图片描述

在这里插入图片描述
最终的读写代码就是这样了, 我们来测试一下
在这里插入图片描述
父进程成功的获得了子进程传来的消息;

管道的特性

1 只能让具有血缘关系的的进程进行进程间通信
2 管道只能单向通信

进程间通信, 本质上同一个资源被多执行流共享, 此时就难免会出现访问冲突
3 父子进程是会协同的, 同步与互斥 – 保护管道文件的数据安全 (后面才会具体讲)
4 管道是面向字节流的(写端不管写了几次,就一直写, 读段也不管写了几次, 有多少就读多少)
5 管道是基于文件的, 而文件的生命周期是随进程的

管道的4种情况

1 读写端正常, 管道如果为空, 读段就要阻塞
在这里插入图片描述
2 读写端正常, 管道如果被写满, 写段就要被阻塞
在这里插入图片描述
我们可以使用 ulimit -a
在这里插入图片描述
可以看到大小为4kb

我们来验证一下
在这里插入图片描述

我们一次写一字节, 看能写多少
在这里插入图片描述
写了65536个字节

可以看到是64KB
在这里插入图片描述
这是为什么呢?

我们通过查看官方文档发现
在这里插入图片描述
3 读端正常, 写端关闭, 那么读段就会读到0 表示读到了文件的结尾, 且不会被阻塞。
在这里插入图片描述
4写端正常写入, 读端关闭, 操作系统就会通过发送信号杀掉正在写入的进程
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

管道的应用场景

在这里插入图片描述

在这里插入图片描述
我们执行这段指令
在这里插入图片描述
可以看到这三个指令同时变成了进程, 然后他们的ppid都是一样的, 说明他们是同一个进程的子进程。

在这里插入图片描述而这个进程的父进程其实就是bash

而指令间的|其实就是匿名管道

上述讲的都是具有血缘关系的进程进行通信, 如果是毫不相关的进程之间要进行通信呢?

命名管道

在这里插入图片描述
在这里插入图片描述
看似这个管道文件是在磁盘上的, 其实他的数据是不会刷新到磁盘的。

在这里插入图片描述
当我们将输出重定向到管道文件的时候, 此时进程就阻塞了;

在这里插入图片描述
我们切换另一个终端, 发现管道的大小还是0, 说明时间上内容并没有被写进去。

在这里插入图片描述
当我们读取管道中的文件后, 之前阻塞的进程就恢复了, 管道里的内容也被正常打印了出来。

其中echo 是一个进程, cat是另外一个进程, 他们两之间没有任何的关系, 可以使用这种命名管道的方式进行通信

理解

  1. 如果两个进程打开同一个文件,虽然会有两个不同的struct_file但是文件其实只加载了一份, 他们两个能看到的内容是一样的。
    所以其实对应的图还是这一个
    在这里插入图片描述
  2. 怎么保证两个进程打开的是同一个文件, 只要保证路径加文件名一样即可
    所以命名管道其实就是通过使用路径+文件名的方案, 让不同进程看到同一份资源, 进而实现进程间通信的。

编写代码

在进程中创建管道, 我们需要用到这个系统调用
在这里插入图片描述
其中第一个参数是路径加名字, 第二个参数是权限
在这里插入图片描述
在进程里删除文件我也需要一个系统调用
在这里插入图片描述
其中的参数就是路径加文件名
在这里插入图片描述
我们先写一段代码
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

我们在sever里加上这个一句话来提醒我们打开文件成功
在这里插入图片描述
在这里插入图片描述
直接运行server却不会打印消息
在这里插入图片描述
而是当client也打开文件的时候, 他才会打印消息, 这说明, 在我们client打开文件之前, server他一直处于这段代码
在这里插入图片描述
这说明server等待写入方打开后, 自己才会打开文件,向后执行 也就是open 阻塞了 反之写入方也一样, 也会等读端打开文件, 否则就会阻塞;

日志

在这里插入图片描述

  • 23
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值