相同: 都在 缓存内核 中 读写 , 先进先出 ,不支持 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、本地进程间