Linux 进程间通信方式都有哪些
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux 进程间通信方式都有哪些相关的知识,希望对你有一定的参考价值。
1、无名管道通信无名管道(pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用,进程的亲缘关系通常是指父子进程关系。
2、高级管道通信
高级管道(popen):将另一个程序当做一个新的进程在当前程序进程中启动,则它算是当前程序的子进程,这种方式我们称为高级管道方式。
3、有名管道通信
有名管道(named pipe):有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
4、消息队列通信
消息队列(message
queue):消息队列是由消息的链表,存放在内核中并由消息队列标识符标识,消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
5、信号量通信
信号量(semophore):信号量是一个计数器,可以用来控制多个进程对共享资源的访问,它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
6、信号
信号(sinal):信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
7、共享内存通信
共享内存(shared
memory):共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。
8、套接字通信
套接字(socket):套接字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。 参考技术A 进程间通信(IPC,Interprocess
communication)是一组编程接口,让程序员能够协调不同的进程,使之能在一个操作系统里同时运行,并相互传递、交换信息。这使得一个程序能够在同一时间里处理许多用户的要求。因为即使只有一个用户发出要求,也可能导致一个操作系统中多个进程的运行,进程之间必须互相通话。IPC接口就提供了这种可能性。每个IPC方法均有它自己的优点和局限性,一般,对于单个程序而言使用所有的IPC方法是不常见的。
1、无名管道通信
无名管道(pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用,进程的亲缘关系通常是指父子进程关系。
2、高级管道通信
高级管道(popen):将另一个程序当做一个新的进程在当前程序进程中启动,则它算是当前程序的子进程,这种方式我们称为高级管道方式。
3、有名管道通信
有名管道(named pipe):有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
4、消息队列通信
消息队列(message
queue):消息队列是由消息的链表,存放在内核中并由消息队列标识符标识,消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
5、信号量通信
信号量(semophore):信号量是一个计数器,可以用来控制多个进程对共享资源的访问,它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
6、信号
信号(sinal):信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
7、共享内存通信
共享内存(shared
memory):共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。
8、套接字通信
套接字(socket):套接字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。
Linux——进程间通信——管道与共享内存
文章目录
进程间通信是什么?
操作系统为用户提供的用于实现进程之间进行通信的方式。
Notes:进程之间是无法直接通信的,因为每一个进程都有自己独立的虚拟地址空间,所以进程具有独立性,无法直接通信。
进程间通信方式种类:管道、共享内存、消息队列、信号量
一、管道
特性
- 半双工通信(可以选择方向的单向通信)
- 管道的生命周期随进程的,进程退出,管道的缓冲区随即被释放。
本质
管道的本质就是在内核中开辟的一块缓冲区(内核中的一块内存),内核的访问只能通过系统调用接口。每个用户都有一个独立的虚拟地址空间,但是内核是共享的。
原理
多个进程通过访问同一块内核中的缓冲区实现通信。
匿名管道
- 匿名管道:缓冲区没有标识符,也就是说匿名管道没有办法被其他进程找到,只能用于只有亲缘关系的进程间通信(父子进程),原因就是匿名管道么得标识符,也就没有办法被其他进程找到,只能通过子进程拷贝父进程的方式获取操作句柄来实现。
Notes:在Linux下,一切皆文件,所有的东西都是当作文件一样进行操作,通过IO操作完成对管道的访问。
- 匿名管道函数:
int pipe(pipefd[2]);这个函数形参列表是一个数组,因为管道是一个半双工通信,所以不能确定到底是读还是写,其中pipefd[0]是读,pipefd[1]用于写。这两个操作句柄不能同时使用。
返回值:成功返回0,失败返回-1。
管道的读写特性:
- 若管道中没有数据,read会阻塞;若管道中的数据写满了,则write会阻塞。
- 所有的管道的读端被关闭,则继续write的话会触发异常导致进程奔溃退出。
- 所有的管道的写端被关闭,则继续read则会读完数据后返回0(返回0就是告诉你,这个管道没有人会给你写入数据了,继续阻塞也没有什么意义)不再阻塞。
- 管道提供字节流传输服务:有序的、可靠的、基于连接的流式传输。
匿名管道的模拟实现
管道符号: | 连接两个命令,将前面命令的打印结果传输给后面的命令进行处理。模拟实现:ps -ef | grep ssh
上述命令中:ps -ef的含义是:获取所有的进程信息,然后输出到标准输出文件。grep ssh的含义是:从标准输入读区数据,进行字符串匹配过滤。如下图:
命名的运行都是创建子进程,让子进程程序替换实现程序功能:
- 在shell进程中,创建管道,创建两个子进程,一个子进程把标准输出重定向到管道写入端,一个程序替换ps;
- 一个子进程把标准输入重定向到管道读取端,替换grep,需要将ps进程数据传输给grep进程–匿名管道。
命名管道
- 命名管道缓冲区具有标识符,可用于同一主机上任意的进程间通信。
- 命名:mkfifo test.fifo
- 命名管道的标识符就是一个可见于文件系统的管道类型文件,多个进程通过打开同一个管道文件,访问同一块内核中的缓冲区实现通信。
- 命名操作:mkfifo + filename :创建一个命名管道文件(文件只是一个标识符,创建一个管道文件,不代表在内核中就有缓冲区,只有当进程中要访问这个缓冲区,才会被开辟)
- 函数操作:int mkfifo(const char *pathname, mode_t mode);
Pathname:文件名称;Mode:创建权限;返回值:成功0,失败-1。 - 打开特性:
若是以只读方式打开管道文件则会阻塞,直到管道被其他进程写的方式打开。
若是以只写方式打开管道文件则会阻塞,直到管道被其他进程以读的方式打开。
总结:管道到底是什么?
答:本质:内核中的一块缓冲区。原理就是多个进程通过访问同一块缓冲区实现数据传输。
分类:匿名管道、命名管道。匿名管道只能适用于具有亲缘关系的进程间通信,命名管道可以用与同一主机上任意进程之间的通信。
特性:可以选择方向的单向通信。管道提供字节流传输服务(有序的可靠的基于连接的一种流式传输,可靠——>“先进先出”,基于连接——>所有读端关闭,write异常,所有写端关闭,则read返回0不再阻塞)。
Notes:
管道自带同步与互斥:
互斥:通过同一时间对临界资源(大家都能访问到的资源,可以理解为公共资源)的唯一访问实现访问操作安全。临界区:对临界资源访问的这段代码区域
同步:通过一些条件判断让进程对临界资源的访问更加合理有序。
互斥的体现:对管道进行写入操作大小不超过一个宏–>PIPE_BUF(4096个字节)保证操作的原子性。
同步的体现:若管道没有数据,则read阻塞;若管道数据满了,则write阻塞。
管道的生命周期随进程—>不人为干预,所有打开管道的进程退出了,则管道资源被释放。
匿名:Int pipe(int pipe[2]);
命名: int mkfifo(const char *pathname, mode_t mode);
二、共享内存:用来实现进程间的数据共享
本质就是一块物理内存
原理:开辟一块物理内存空间,多个进程将同一块内存通过页表映射到自己的虚拟地址空间,通过自己的虚拟地址空间直接进行访问。
操作流程:
1.创建或打开共享内存
2.将共享内存映射到进程的虚拟地址空间
3.通过映射的虚拟地址进行各种内存操作
4.解除映射关系
5.删除共享内存
共享内存的生命周期随内核,不与进程同进退。
操作接口:
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
Key:标识符,多个进程通过相同的标识符打开同一块共享内存
Size:创建时候所开辟空间大小,如果已经内存存在,则被忽略。(以内存页为单位,默认是:4096个字节)
Shmflg:打开方式+创建权限(IPC_CREAT | IPC_EXCL | 0664)
返回值:成功:返回非负整数–>操作句柄;失败返回-1。
void *shmat(int shmid, const void shmaddr, int shmflg);
Shmid:shmget返回的操作句柄
Shmaddr:映射地址–通常为NULL;
Shmflg:映射成功后的访问方式:SHM_RDONLY-只读;0-读写
返回值:成功返回映射后的首地址,失败返回(void)-1;
int shmdt(const void *shmaddr); 解除映射关系。Shmaddr:映射后的首地址。
返回值:成功0,失败-1;
int shmctl(int shmid, int cmd, struct shmid_ds *buf);删除共享内存
Shmid:shmget返回的操作句柄,cmd:操作类型–IPC_RMID–标记共享内存为被销毁状态。Buf:同于设置或获取共享内存信息,不使用则置null,返回值对于IPC_RMID则是成功0,失败-1;
共享内存总结
本质原理:开辟一块内存空间,多个进程将同一块内存映射到虚拟地址空间,通过自己虚拟地址进行访问,进而实现进程间通信。
特点:最快的进程间通信方式;共享内存的生命周期随内核
注意事项:共享内存是一个临界资源,对共享内存的操作需要注意安全问题。
共享内存通过虚拟地址直接访问虚拟内存实现数据共享,相对于其他方式需要将数据拷贝到内核,使用时拷贝到用户态,少了两次数据拷贝操作。
有个小练习:共享内存代码实现
运行上述两个代码的时候,可以实现使用共享内存实现进程间通信。
Notes:
ipcs 查看进程间通信资源/ipcrm 删除进程间通信资源
-m 针对共享内存的操作
-q 针对消息队列的操作
-s 针对消息队列的操作
-a 针对所有资源的操作
以上是关于Linux 进程间通信方式都有哪些的主要内容,如果未能解决你的问题,请参考以下文章