进程间通信方式有哪些?
前言
进程能够单独运行并且完成一些任务,但是也经常免不了和其他进程传输数据或互相通知消息,即需要进行通信,本文将简单介绍一些进程之间相互通信的技术--进程间通信(InterProcess Communication,IPC)。由于篇幅有限,本文不会对每一种进行详细介绍。
概览
进程间通信常见方式如下:
管道
FIFO
消息队列
信号量
共享内存
UNXI域套接字
套接字(Socket)
管道
管道是一种古老的IPC通信形式。它有两个特点:
半双工,即不能同时在两个方向上传输数据。有的系统可能支持全双工。
只能在父子进程间。经典的形式就是管道由父进程创建,进程fork子进程之后,就可以在父子进程之间使用了。
使用popen函数和pclose函数结合来执行系统命令,就用到了管道,它们声明如下:
FILE *popen(const char *command,const char *type);
int pclose(FILE *stream);
system()函数虽然也能够执行系统命令,但是无法获取执行状态码,而执行系统命令本质上就需要创建子进程来完成,因此利用管道可以很方便的获取子进程的输出内容。本文不详细展开。
我们看一个简单的使用管道的例子,这里使用了pipe函数来创建管道:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#define MAX_LEN 128
int main(void)
{/*0为读,1为写*/int fd[2] = {0}; //描述符pid_t pid = 0;char line[MAX_LEN] = {0};int n = 0;/*创建管道,需要传入两个文件描述符*/if(pipe(fd) < 0){perror("create pipe failed\n");return -1;}/*fork子进程*/if((pid = fork()) < 0){perror("fork failed\n");return -1;}/*父进程*/else if(pid > 0){/*关闭管道的写描述符*/close(fd[1]);/*从管道读取数据*/n = read(fd[0],line,MAX_LEN);printf("read %d bytes from pipe :%s\n",n,line);}/*子进程*/else{/*关闭管道的读描述符*/close(fd[0]);/*向管道写入数据*/write(fd[1],"www.yanbinghu.com",sizeof("www.yanbinghu.com"));}return 0;
}
在程序中,我们创建了一个管道,父进程关闭了写通道,子进程关闭读通道;子进程向管道内写入字符串,而父进程从管道中读取字符串并输出。
运行结果:
read 18 bytes from pipe :www.yanbinghu.com
FIFO
FIFO也被称为命名管道,与管道不同的是,不相关的进程也能够进行数据交换。
涉及FIFO操作主要函数为:
int mkfifo(const char *path, mode_t mode);
而FIFO也常常有以下两个用途:
无需创建中间临时文件,复制输出流
多客户-服务进程应用中,通过FIFO作为汇聚点,传输客户进程和服务进程之间的数据
我们看一个简单的例子,写进程代码如下:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#define FIFO "/tmp/fifo"
#define MAX_LEN 128
int main(void)
{int writeFd;char line[MAX_LEN] = {0};if(mkfifo(FIFO,S_IRUSR|S_IWUSR) < 0 && (errno != EEXIST)){perror("make fifo failed:");return -1;}/*关闭管道的读描述符*/writeFd = open(FIFO,O_WRONLY,0);/*向管道写入数据*/write(writeFd,"www.yanbinghu.com",sizeof("www.yanbinghu.com"));close(writeFd);return 0;
}
它首先创建了一个FIFO,并且打开后,往里面写入字符串,然后关闭退出。
读进程代码如下:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include<fcntl.h>
#define FIFO "/tmp/fifo"
#define MAX_LEN 128
int main(void)
{int readFd,n;char line[MAX_LEN] = {0};/*打开FIFO,这里打开可能失败,应该要对返回值处理*/readFd = open(FIFO,O_RDONLY,0);/*从FIFO读取数据*/n = read(readFd,line,MAX_LEN);printf("read %d bytes from pipe :%s\n",n,line);close(readFd);/*删除FIFO*/unlink(FIFO);return 0;
}
它先打开一个已知的FIFO,然后从FIFO中读取数据。
在一个终端先运行写进程,然后运行读进程,结果如下:
read 18 bytes from pipe :www.yanbinghu.com
我们可以看到,两个没有亲缘关系的进程可以通过FIFO进行通信。
消息队列
消息队列可以认为是一个消息链表,存储在内核中,进程可以从中读写数据。与管道和FIFO不同,进程可以在没有另外一个进程等待读的情况下进行写。另外一方面,管道和FIFO一旦相关进程都关闭并退出后,里面的数据也就没有了,但是对于消息队列,一个进程往消息队列中写入数据后退出,另外一个进程仍然可以打开并读取消息。消息队列与后面介绍的UNIX域套接字相比,在速度上没有多少优势。
信号量
信号量是一个计数器,它主要用在多个进程需要对共享数据进行访问的时候。考虑这一的情况,不能同时有两个进程对同一数据进行访问,那么借助信号量就可以完成这样的事情。
它的主要流程如下:
检查控制该资源的信号量
如果信号量值大于0,则资源可用,并且将其减1,表示当前已被使用
如果信号量值为0,则进程休眠直至信号量值大于0
也就是说,它实际上是提供了一个不同进程或者进程的不同线程之间访问同步的手段。
共享内存
共享内存允许多个进程共享一个给定的存储区,由于它们是共享一块内存数据,因此其速度非常快。但是需要另外提供手段来保证共享内存的同步访问,例如它可以用到前面所提到的信号量来实现访问同步。
UNIX域套接字
UNIX域套接字和套接字很相似,但是它有更高的效率,因为它不需要执行协议处理,例如计算校验和,发送确认报文等等,它仅仅复制数据。
当然,它也只适用于同一台计算机上的进程间通信。
例如redis服务配置unixsocket启动后,通过redis-cli的-s参数就可以指定UNIX域套接字,连接到redis服务器。
$ redis-cli -s /tmp/redis.sock
redis /tmp/redis.sock>
它会比使用网络套接字的速度要快。
网络套接字
这个不用多说,它利用网络进行通信,与前面所提到的通信方式不同的是,它能用于不同计算机之间的不同进程间通信。
总结
本文简单介绍了进程间通信的常见方式,其中对管道和命名管道我们使用了一个例子来简单说明,因为我们可能会经常见到它。对于FIFO,最后一个引用它的进程终止时,留在FIFO的数据也将会被删除,而对于消息队列却不是这样,它会一直留到被显示删除或者系统自举,另外消息队列于其他方式相比并没有特别的优势。而信号量实际上常用于共享数据的同步访问。共享内存在进程间传递数据非常高效,但是系统没有对访问进行同步,因此还需要另外实现数据的访问同步。套接字(socket)是应该目前应用最广泛的进程间通信方式。
本文仅做简单介绍,实际内容远不止此。PC端访问阅读原文地址效果更佳。本文最新内容地址进程间通信方式有哪些
参考:
《Unix环境高级编程》
《unix网络编程卷2:进程间通信》
《深入Linux内核架构》
相关阅读:
面试必问:进程和线程有什么区别?
关注公众号【编程珠玑】,获取更多Linux/C/C++/Python/Go/算法/工具等原创技术文章。后台免费获取经典电子书和视频资源
进程间通信方式有哪些?相关推荐
- dat关闭某进程_超详细解析!工程师必会的Linux进程间通信方式和原理
▍进程的概念 · 进程是操作系统的概念,每当我们执行一个程序时,对于操作系统来讲就创建了一个进程,在这个过程中,伴随着资源的分配和释放.可以认为进程是一个程序的一次执行过程. ▍进程通信的概念 · 进 ...
- 两个不同的进程 虚拟地址相同_记一次阿里面试题:都有哪些进程间通信方式?麻烦你不要再背了...
1 管道 学习软件工程规范的时候,我们知道瀑布模型,在整个项目开发过程分为多个阶段,上一阶段的输出作为下一阶段的输入.各个阶段的具体内容如下图所示 最初我们在学习Linux基本命令使用的时候,我们经常 ...
- 记一次阿里面试题:都有哪些进程间通信方式?麻烦你不要再背了
1 管道 学习软件工程规范的时候,我们知道瀑布模型,在整个项目开发过程分为多个阶段,上一阶段的输出作为下一阶段的输入.各个阶段的具体内容如下图所示 最初我们在学习Linux基本命令使用的时候,我们经常 ...
- [【转载】 linux进程间通信方式
目录 目录 进程通信的目的 Linux 进程间通信(IPC)的发展 linux使用的进程间通信方式 管道( pipe ) 信号量( semophore ) 消息队列( message queue ) ...
- IPC 进程间通信方式——管道
进程间通信概述 数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几兆字节之间 共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到. 通知时间: ...
- 进程间通信方式有哪些-Linux进程间通信
进程间通信:(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息: 进程间的通信方式: 管道(包括无名管道和命名管道).消息队列.信号量.共享内存.套接口. ...
- Android——进程间通信方式
0. 前置知识 其实android中追根溯源只有两种进程间通信方式,其他的方式都是通过封装这两种方式而得到的: Binder与Socket Android--Binder机制. Android中Soc ...
- zeromq源代码分析2------线/进程间通信方式
本文我们讲一下zeromq的线/进程间通信方式. 在zeromq源代码分析1中我们分析了zeromq的基本工作流程.我们了解到了zeromq的线/进程间通信的方式为消息传递. zeromq中的各线程间 ...
- Android 进程间通信方式和线程间通信方式
1.进程和线程 进程:是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位. 线程:是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独 ...
- 线程间通信方式Linux,线程间的通信、同步方式与进程间通信方式
1.线程间的通信方式 使用全局变量 主要由于多个线程可能更改全局变量,因此全局变量最好声明为volatile 使用消息实现通信 在Windows程序设计中,每一个线程都可以拥有自己的消息队列(UI线程 ...
最新文章
- FLINK源代码调试方式
- SANBoot安装系统
- mysql主从状态异常解决办法
- 解决Loadrunner报not writing pre_cci.ci问题
- python3 中递归的最大次数
- Redisson 是如何实现分布式锁的?
- 【自动化__持续集成】___java___重载
- webview重新加载(reload)或者发起 redirect request导致js和objc代码之间的bridge失联解决方案(亲测有效)...
- fastcgi协议分析与实例
- ElasticSearch简介与安装
- 银行流水你真的会看吗?
- selenium与python自动化测试模拟登录百度
- 玩转 SpringBoot 2 快速整合拦截器
- fgets,cin. getline被跳过
- UVA12015 Google is Feeling Lucky【最值+排序】
- Java计算机毕业设计电竞教育公司源码+系统+数据库+lw文档
- Android 模拟器安装及使用教程
- 质检动真格,你的本科毕业论文该怎么做?
- 「Activiti精品 悟纤出品」Activiti7 Getting Started-摸石头过河 - 第323篇
- 还在傻傻的数star、数fork吗?3秒钟教会你如何查看GitHub项目活跃度,是死是活一眼便知