进程通信

2021-12-05 22:30:31 浏览数 (1)

相同: 都在 缓存内核读写先进先出 ,不支持 lseek 之类文件定位操作

1、匿名管道

$ ps auxf | grep mysql 用完就销毁| 就是一个 管道 ,将前一个命令(ps auxf)输出,作为后一命令(grep mysql)输入, 管道传数据是单向,如相互通信,要两个

2、命名管道 FIFO

$ mkfifo myPipe(名) 用前要mkfifo 命令创建,指定管道名,数据先进先出1) 基于“Linux一切皆文件”,管道也 文件 ,ls 看, 文件类型是 p ,就是 pipe(管道) 意思

2)往 myPipe 写入数据: 因为内容没被读,只有读后,命令才正常退出

3)读出 了,echo 命令正常退出

3、创建原理

1)匿名管道 创建, 通过 int pipe(intfd2) 系统调用:两个描述符:管道 读取端 fd0写入端 fd1 。ps:匿名管道是 特殊文件 ,只在 内存不存文件系统

2)管道,就是内核里一串缓存 。读写都在缓存内核中, 传数据无格式的流大小受限

3)跨进程通信实现: fork 创建子进程, 复制父进程文件描述符 ,两个进程各有两个「 fd0 与 fd1」,通过各自fd

读写同一管道文件

4)避免混乱:父进程 :关读 fd0,保留写fd1 子进程:关写 d1,保留读fd0所以, 双向通信,应两个管道

5)到这里,仅解析父子进程通信, 但shell 里面并不是这样

shell 里:执行 A | B命令时,都是 shell 创建的子进程, 不存父子关系,父进程都是 shell

ps:shell 里能使用一个管道搞定的事情,就不要多用一个管道,减少创建子进程开销

二、消息队列

解决频繁地交换数据问题, 内核中的消息链表

1、发时 ,分成一个个消息体(数据块),用户自 定义数据类型,固定大小 ,不像 管道无格式字节流数据

读后 ,内核 删除 消息体

2、生命周期:随内核 ,没有 释放 消息队列或没 关闭操作系统管道 随进程 结束销毁

3、不足:通信不及时,大小限制用户态内核态数据拷贝开销:写数据内核队列时 ,从用户态拷到内核态过程, 读同理 ,从内核到用户

不适合大数据传输 ,消息体、队列总长都有限制。Linux 内核中有MSGMAX 和 MSGMNB 消息和队列最大长,字节为单位

三、共享内存

解决 用户态与内核间的 消息拷贝

1、内存管理: 进程有自己独立的 虚拟内存空间不同进程虚拟内存 映射到 不同物理内存 中。即使进程 A

B 虚拟地址一样,其实访问的是不同的物理内存地址,对于数据的增删查改互不影响。

2、共享内存 机制 :就是拿出一块虚拟地址空间来,映射到相同的物理内存中 。这样写入,另一进程马上能看到,

不需拷贝,传来传去,提高通信速度

四、信号量

共享内存问题,同时修改同一共享内存,冲突。 信号量解决

信号量:整型计数器, 表示资源的数量,实现进程 间互斥与同步, 而不是用于缓存进程间通信数据

1、控制信号量两种原子操作:

1)P 操作 ,减 -1,减后: < 0被占用 ,进程阻塞等待; > = 0可用,继续执行

2)V 操作 ,加 1, <= 0,有阻塞唤醒运行; > 0,没有阻塞P 在进入共享资源之 V 离开 成对出现

2、例:两进程互斥访问共享内存,初始化信号量1

先P 操作,信号量变 0,可用,访问共享内存此时B 也访问, P 操作, -1被阻塞。A 完V 操作,恢复为 0,唤醒阻塞中B,B 完成执行 V,恢复1

例2,A 负责生产数据,B 是负责读,有顺序。初始化信号量可为 0

五、信号

上面都是常规工作模式。 异常用「信号」通知进程, 唯一异步通信机制。 ps: 跟信号量虽然名字相似,用途完全不一样

1、Linux 操作系统, 为响应各种各样事件,提供几十种信号, kill -l 命令,查看所有

2、 给进程发送信号终端 输入组合键: Ctrl C 产生 SIGINT 信号,终止进程;Ctrl Z 产生 SIGTSTP 信号, 停止进程,未结束

如果进程在后台运行,用kill PID 号 kill -9 1050 ,立即结束

3、进程对信号处理方式

1)执行默认操作: Linux 对每种信号规定默认操作,SIGTERM 信号,终止。 Core Dump ,终止进程后,通过CoreDump 将当前进程的 运行状态保存在文件里 ,方便事后分析

2.捕捉信号: 定义信号处理函数。信号发生,执行相应函数

3.忽略信号 。不做任何处理。SIGKILL 和 SEGSTOP无法捕捉和忽略,用于任何时候中断或结束某一进程。

六、Socket

跨网络不同主机 上进程间通信(也可同主机) ,要 Socket

1、创建 socket 系统调用int socket(int domain,int type, int protocal)

domain:协议族 ,如 AF_INET 用于 IPV4、AF_INET6 用于 IPV6、AF_LOCAL/AF_UNIX 用于本机;

type :通信特性 ,如 SOCK_STREAM 表示字节流,对应 TCP、SOCK_DGRAM 表示数据报,对应 UDP、SOCK_RAW表示原始套接字;protocal (基本废弃):写成 0 即可,原本是用来指定通信协议的,通过前两个完成

2、不同socket 类型,通信方式不同

实现 TCP 字节流 通信:socket 是 AF_INET 和 SOCK_STREAM;

实现 UDP 数据报 通信:socket 是 AF_INET 和 SOCK_DGRAM;

实现 本地进程间 通信:「本地字节流 socket 」类型是 AF_LOCAL 和 SOCK_STREAM,「本地数据报 socket 」类型是AF_LOCAL 和 SOCK_DGRAM。ps:AF_UNIX 和 AF_LOCAL 是等价的,所以 AF_UNIX 也属于本地 socket;

3、三种通信编程模式

(1)TCP 协议通信socket 编程模型

1)服务端和客户端初始化 socket,得到文件描述符;

2)服务端调 bind ,绑定IP 地址和端口; 调 listen 监听; 调accept ,等待客户端连接;

3)客户端调 connect ,向服务器端的地址和端口发起连接请求;

4)服务端 accept 返回用于传输的 socket 文件描述符;ps:连接成功 返回已完成连接socket ,通过read 和 write

读写,像往文件流里面写东西一样

5)客户端调 write 写入数据;服务端调用 read 读取数据;

6)客户端 断开连接时调用 close ,那么服务端 read 读取数据时, 读到EOF,处理完close监听socket 和 真正 传数据socket (已完成连接 socket),是「 两个 」 socket

(2)针对 UDP 协议通信的 socket 编程模型

1) 只要 IP 地址端口号、bind ,UDP没连接,不需要三次握手,不需像 TCP 调listen 和 connect,。

2) 每次通信, 调sendto 和 recvfrom ,传入目标主机的 IP 地址端口

(3)本地进程间通信socket 编程模型

用于 同一主机通信 的,

1)接口和 IPv4 、IPv6 套接字编程一致,支持 「字节流」和「数据报」 两种协议;效率大大高于 IPv4 和 IPv6 字节流、数据报socket 实现;本地 字节流 socket ,socket 类型AF_LOCAL 和 SOCK_STREAM。本地 数据报 socket ,AF_LOCAL 和 SOCK_DGRAM。

2) 两个bind 时绑定一个本地文件, 不像 TCP 和 UDP 要绑定 IP 地址和端口,最大区别

总结

每个进程都共享一个内核空间,来通信

1、Linux 内核提供「匿名管道」和「命名管道」:都写入 缓存在内核 中,另一个进程也从内核读, 先进先出 ,不支持 lseek 文件定位

匿名: 「|」竖线就是匿名管道,通信数据 无格式的流并且大小受限单向 ,双向要建两个管道, 只能用于父子关系通信,随着进程创建而建,终止而消失

命名管道: 突破父子限制,使用前提,要文件系统创建类型 p 的设备文件。

2、消息队列:

解决管道无格式的字节流的问题,实际是保存在内核「消息链表」,用户可自定义消息体,发时被分成,一个个独立消息体,接时保持一致,不是最及时的,读写要经过用户态与内核态之间的拷贝过程。

3、共享内存:解决 拷贝开销, 直接分配共享空间,进程可直接访问 ,提高速度,缺点:多进程竞争同个共享资源错乱

4、信号量:实现 互斥访问。实际是计数器(资源个数), P 和 V 操作控制

5、信号唯一异步通信机制 ,在 应用 进程和 内核直接交互,内核用信号来通知用户,进程发生了哪些系统事件, 三种方式响应信号 1. 执行默认操作、2. 捕捉信号、3. 忽略信号 。ps:SIGKILL 和SEGSTOP无法捕捉和忽略,方便任何时候结束进程

6、Socket: 与不同主机的进程间通信,那么就需要 通信了 。根据Socket不同类型,分为三种通信方式, TCP、UDP、本地进程间

0 人点赞