进程间通讯
1. 操作系统的进程间通讯
进程间通讯 根据名字描述就是进程之间的信息交换
进程间的互斥和同步 由于交换的信息量少 被归结为低级的进程间通讯
高级通讯机制可以分成三类
一. 共享存储器系统
- 基于共享数据结构的方式
通过公用某些数据结构来进行通信 低效的 适用于少量的信息传递
- 基于共享存储区的方式
- 向系统申请一个共享存储区的分区 拿到分区的描述符
- 通过描述符把申请的共享分区连接到自己的进程
- 进行读写操作 实现数据传递
二. 消息传递系统
-
进程间的通信是以格式化的消息(message)为单位的
message 操作系统提供的一组通信命令
实现了大量数据的传递 隐藏了通信的细节
-
实现方法
直接通信
利用OS提供的发送命令 直接将消息发送给目标进程
Send(Receiver,message) Receive(Sender,message) 发送进程和接收进程需要显示的提供对方的标识符
间接通信
通过共享数据结构的实体 暂存发送的消息 允许接收方随时读取 类似信箱的功能 可以非实时的
- 信箱的创建和撤销 消息传递系统 进程调用的都是系统的原语 创建时提供名字 属性(公用 私有 共享)
- 消息发送和接收 必须使用共享信箱 Send(mailbox,message) Receive(mailbox,message)
信箱的类型 属性决定的
1.私有的
进程的一部分 进程消失就消失 只有创建者可以读取 其他的只能发送
- 公共的
系统创建的 系统中所有的核准进程使用 发送和读取 系统运行期间都存在
- 共享的
信箱某进程创建 发送和接收之间存在4种关系
1对1
1对多
多对1
多对多
三. 管道通信系统
共享文件 一个读的进程 一个写的进程 连接起来实现进程间通讯 pipe
管道机制需要有三方面的协调能力
- 互斥
- 同步
- 确定对方是否存在
linux下的进程间通讯
IPC
Inter-Process Communication
- 管道 pipe
什么是管道 通过一个进程的输出连接到另一个进程的输入 这就是管道
linux 下是怎么实现的 记住两个函数
FILE * popen(const char * command , const char * opend_mode);
int pclose(FILE * stream_to_close);
popen函数 第一个参数是你要启动的进程名 第二个参数opend_mode是打开方式(只有r w两种)
如果是r的时候 被启动的进程的输出可以被当前进程使用 popen函数的返回值是一个FILE* 文件流指针 可以通过fread 方法来读取被调用程序的输出
pclose 函数 popen函数启动的进程结束的时候 通过pclose 关闭与之关联的文件流 返回值在启动的进程结束后才得到 如果调用pclose的时候 被启动的进程仍在进行 那么pclose的调用将等待结果
pipe 是popen的底层实现
-
命名管道 FIFO
这东西有点像socket 只不过文件是存在的了 比如A进程想访问B进程 那么在B进程中创建一个文件
并将内容写入
然后在A进程中打开并读取这个文件的内容 A进程也可以先进行打开读取 他会阻塞直到有数据才会继续read
int mkfifo(const char * filename,mode_t mode);
int mknod(const char * filename,mode_t mode | S_IFIFO, (dev_t 0));
通过上面的函数创建fifo管道 与pipe对比 FIFO是以命名文件的形式存在的 pipe是文件描述符 所以操作他的时候也必须是open和close 打开关闭文件
进程间通讯机制
IPC
Inter-Process Communication
以下几个概念是进程间通讯的机制
- 信号量 特殊的符号量 只允许对他进行等待 和 发送信号这两种操作
作用是对临界代码拥有资源独占式的访问权
-
共享内存 允许两个不相关的程序 访问同一块共享内存 程序员负责锁的问题
-
消息队列
通过 int msgget(key_t key,int msgflag) 函数来创建和访问一个消息队列 第一个名字 第二个权限
- int msgget(int key_t key,int msgflag) 创建一个消息队列 返回值是消息队列标识
参数1 给消息队列命名
参数2 权限值
- int msgsnd(int msgid,const void * msg_ptr, size_t msg_sz,int msgflag) 发送消息
参数1 是通过get时候的返回值也就是消息的标识符
参数2 一个准备接收消息的指针
参数3 消息的长度
参数4 消息的接收优先级
- msgrcv(int msgid,const void * msg_ptr, size_t msg_sz,long int msgtype, int msgflag) 消息队列中获取消息
参数1 是通过get时候的返回值也就是消息的标识符
参数2 一个准备接收消息的指针
参数3 消息的长度
参数4 消息的接收优先级
参数5 消息中没有相应类型的消息可以接收时发生
- msgctl(int msgqid, int command,struct msqid_ds *buf)
参数1 消息队列的标识符
参数2 采取的动作 删除 赋值等
参数3 参数2操作的结构体
android Binder
android binder机制困扰我好多天 我一直也没弄明白 我学习的方式 是通过看书 跟着书里对binder的源码进行分析 这种学习方式对我来说是错的 先说下错的学习思路
1. 首先书中介绍了android binder机制的几个组成部分
- /dev/binder 驱动 dev下放的大多数都是驱动
- service manger 作用是守护进程 并充当client 和 server的服务器
- server 你要交互的服务进程 或者你自己的写的service
- client 你自己的写的进程
书中根据binder.c service manger.c 各种源码分析 给你讲解 service manger 怎么成为 dev/binder的守护进程 怎么又成了整个server 和client的服务端的 讲了好多的结构体 然后我就蒙了
后来学习的过程总结
1. 首先我要干啥 进程间通讯呀
- 我们已知的条件 IBinder 这个比较基础的 大家都清楚
- bindservice 时候 在onServiceConnection中 可以得到这个IBinder对像
- 你自己定义的service里 在onBInd 方法中得到IBInder 对象
根据上边我们熟悉的东西 我们可以大概知道 BInder机制共享的是对象
那和上边的几种进程间通讯对比下
- 共享寄存器
跟他有点像 BInder是对象 他是共享一个数据结构或者共享一个寄存器的分区 通过对他的读写来进行通信
- 消息传递系统
通过系统的原语 进行send receive 这种 需要知道对方进程的标识符
linux下是通过申请队列 然后写消息 接收消息
和他也有相似的地方 - 管道
进程之间 未命名的只能是父子关系的进程通信 通过打开一个文件描述符
命名管道 是通过指定的进程标识符 可以进行通信
- Socket
通过协议控制
网友评论