IPC(进程间通信)
Linux下的多个进程间的通信机制叫做IPC,它是多个进程之间进行互相沟通的一种方法
通过进程间通信实现不同进程之间传播和交换信息
进程间通信(IPC)的目的总结
1:数据传输
2:资源共享
3:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件
4:进程控制
进程间通信的方式
在Linux下有多个进程间通信的方法:半双工管道、FIFO(命名管道)、消息队列、信号量、共享内存、socket、信号等
适用于一台机器上
1:管道(无名和命名)
2:信号
kill -l #查看机器支持的信号
3:消息队列
4:共享内存
5:信号量
操作系统中是PV操作
常用于不同机器间通信
6:socket(网络通信)
各种通信的特点描述
管道|
无名管道可用于具有亲缘关系进程间的通信
命名管道可用于无亲缘关系进程间的通信
信号signal
信号是比较复杂的通信方式,用于通知接受进程有某种事件发生
异步通信
signal和kill
sigaction和sigqueue
消息队列
消息队列是消息的链表
优点
消息队列克服了信号承载信息量少,
管道只能承载无格式字节流以及缓冲区大小受限等缺点
共享内存
使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。
注意:往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
信号量
主要作为进程间以及同一进程不同线程之间的同步手段
套接口(Socket)
更为一般的进程间通信机制,可用于不同机器之间的进程间通信
网络通信
案例
管道 |
---|
管道是一种把两个进程之间的标准输入和标准输出连接起来的机制
shell中管道用”|”表示
who | wc -l
#将左侧who命令的结果,作为管道右侧命令的输入
进程创建管道,每次创建两个文件描述符来操作管道。
其中一个对管道进行写操作,另一个描述符对管道进行读操作。
注意:
某些特定的IO操作管道是不支持的,例如偏移函数lseek()
#查看内核缓冲区
ulimit -a
可以查看PIPE_BUF(内核管道缓冲区)的大小,这是内核设定的为8*512byte=4k
pipe capacity(管道)16*4k=64K
int pipe(int pipefd[2],int flags);
创建一个管道,并对管道的两端作为文件描述符进行赋值
pipefd[0] 管道的读取端—pipefd[0]
pipefd[1] 管道的写入端—pipefd[1]
*在使用管道的时候,如果使用了管道的输入端,那么就需要将管道的输出端关闭,反之一样
管道特点
1:只能在有亲缘关系的进程之间进行通信(也就是在父子进程之间通信)
2:单向通信一个读端,一个写端,如果要双向通信就要建立两个管道
3:接收数据流,与数据格式无关
4:一般而言,进程退出,管道释放,因此管道的生命周期随进程
5:同步互斥原则,内核会对管道操作进行同步和互斥
无名管道的缺点:
1、没有名字,因此无法使用open()打开
2、只能用于亲缘进程间(如父子进程、兄弟进程、祖孙进程等)通信
3、半双工工作方式,读写端是分开的,pipefd[0]为读端,pipefd[1]为写端
4、写入操作不具有原子性,因此只能用于一对一的简单通信
5、不能用lseek()来定位
案例
pipecapacity1.c
运行结果为:(因为只写入不读取,所以存取容量达到上限,导致管道容量达到上限64k)
pipe1.c
运行结果为:fork父子进程间通信
pipe2.c
运行结果为:
pipe2.c的功能相当于下面的命令
ls -l | wc
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191015160911999.png)
命名管道
FIFO
int mkfifo(const char *pathname, mode_t mode);
创建一个命名管道文件,通过管道文件的数据写入或者读取来实现进程间的通信
pathname 管道文件名称
mode 管道文件的创建权限
mkfifo仅仅是创建一个命名管道,如果要使用这个管道,那么需要
open打开这个管道文件
原理
命名管道提供了一个路径名与之关联,以FIFO的文件形式存在于文件系统中,
在文件系统中产生一个物理文件,其他进程只要访问该文件路径,就能彼此通过管道通信。
#通过命令创建管道
mkfifo my-named-pipe
#查看my-named-pipe的类型是p
ll或ls -a
第一个p代表文件类型是管道
#通过命令使用管道
#终端1,数据写入管道,此时进入阻塞,等待另一端读取
echo “yanda” > my-named-pipe
#终端2,读取管道中的数据,读取完之后终端1正常退
cat my-named-pipe
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191015162146467.png)
案例
fifo1.c
消息队列
消息队列是内核地址空间中的内部链表,通过linux内核在各个进程之间传递内容,
消息顺序地发送到消息队列中,并且以几种不同的方式,从队列中获取,
每个消息队列可以用IPC标识符唯一的进行标识,内核中的消息队列是通过IPC的标识符来区别的,
不同的消息队列之间是相互独立的,每个消息队列中的消息又构成一个独立的链表。
基本概念
消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。
每个数据块都被认为含有一个类型,接收进程可以独立地接收含有不同类型的数据结构。
我们可以通过发送消息来避免命名管道的同步和阻塞问题。
但是消息队列与命名管道一样,每个数据块都有一个最大长度的限制。
ipcs和ipcrm命令(重点)
ipcs提供IPC设备的信息
ipcs -m 查看系统共享内存信息
ipcs -q 查看系统消息队列信息
ipcs -s 查看系统信号量信息
ipcs [-a] 系统默认输出信息,显示系统内所有的IPC信息
ipcrm
通过指定ID删除IPC资源,同时将与IPC对象关联的数据一并删除,只有超级用户或IPC资源创建者能够删除
ipcrm -M shmkey
移除用shmkey创建的共享内存段
ipcrm -m shmid
移除用shmid标识的共享内存段
ipcrm -S semkey
移除用semkey创建的信号量
ipcrm -s semid
移除用semid标识的信号量
ipcrm -Q msgkey
移除用msgkey创建的消息队列
ipcrm -q msgid
移除用msgid标识的消息队列
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#创建和访问一个消息队列
int msgget(key_t key, int msgflag);
key:某个消息队列的名字,用ftok()产生 (函数ftok的返回值)或IPC_PRIVATE
案例
msgget1.c
运行结果为: