Android Framework- IPC基础知识

156 阅读6分钟

Android IPC的几种方式

名称优点缺点场景
Bundle简单易用只能传输Bundle支持的数据四大组件间的进程间通信
文件共享简单易用不适合高并发场景,并且无法做到进程间的即使通信无并发访问情形,交换简单的数据实时性不高的场景
AIDL功能强大,支持一对多并发通信,支持实时通信使用稍复杂,需要处理好线程同步一对多通信且有RPC需求
Messenger功能一般,支持一对多串行通信,支持实时通信不能很好处理高并发情形,不支持RPC,数据通过Message进行传输,因此只能传输Bundle支持的数据类型低并发的一对多即时通信,无RPC需求,或者无须返回结果的RPC需求
ContentProvider在数据源访问方面功能强大,支持一对多并发数据共享,可通过Call方法扩展其他操作可以理解为受约束的AIDL,主要提供数据源的CRUD操作一对多的进程间的数据共享
Socket功能强大,可以通过网络传输字节流,支持一对多并发实时通信实现细节稍微有点繁琐,不支持直接的RPC网络数据交换

比如调用bindService() ,实现 ServiceConnection 中也会返回一个IBinder

AIDL 关键字

interface ITest {
   
           oneway  void send(in  String name ,out  String name2 ,inout String name3);
​
}
  • oneway

oneway 关键字用于修饰远程调用的行为,被oneway修饰了的方法不可以有返回值,也不可以有带out或inout的参数。 使用oneway时,远程调用不会阻塞;它只是发送事务数据并立即返回。接口的实现最终接收此调用时,是以正常远程调用形式将其作为来自 Binder 线程池的常规调用进行接收。

  • in,out,inout介绍

in、out、inout表示跨进程通信中数据的流向(基本数据类型默认是in,非基本数据类型可以使用其它数据流向out、inout)。in 表示数据只能由客户端流向服务端。(表现为服务端修改此参数,不会影响客户端的对象)。out 表示数据只能由服务端流向客户端。(表现为服务端收到的参数是空对象,并且服务端修改对象后客户端会同步变动)

  • inout

    inout 则表示数据可在服务端与客户端之间双向流通。(表现为服务端能接收到客户端传来的完整对象,并且服务端修改对象后客户端会同步变动)

Epoll

以前面试问消息机制,问到最后经常问为啥 不会卡死 ,其实底层就是epoll 原理。

理论上真没消息的时候 他是阻塞的,但是16ms的一次刷新,触摸等都会唤醒。没消息就wait。

#include <sys/epoll.h>
//用于控制已经创建的epoll实例上的文件描述符的事件监控
int epoll_ctl(int __epoll_fd, int __op, int __fd, struct epoll_event* __event);
//阻塞等待直到至少一个文件描述符处于就绪状态(比如可读、可写)。当有事件发生时,它返回一个包含就绪文件描述符及其事件的数组。你可以指定超时时间来避免无限期阻塞。  __events 代表要监听的事件类型
int epoll_wait(int __epoll_fd, struct epoll_event* __events, int __event_count, int __timeout_ms);
​
//创建一个epool ,并设置他观察的文件的最大数量
int epoll_create(int size);
​
​
/** events可以是以下几个宏的集合:
EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
EPOLLOUT:表示对应的文件描述符可以写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR:表示对应的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被挂断;
EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里
*/
struct epoll_event {
  uint32_t events;
  epoll_data_t data;
}

Epool 是多路复用的一种。它核心思想收集进程感兴趣的全部描述符,然后调用一个函数,当这些描述符中的一个或多个准备好 I/O 时,函数返回并告知进程是哪些描述符准备好了。此时进程只需要去这些准备好的描述符上操作即可。 避免了之前那种 while(true) 和多连接问题。当然在某种程度上,我们可以简单理解为观察者模式,实际上 epoll利用了Linux内核的事件通知机制。

Socketpair

socketpair是一个系统调用,用于在同一台机器上的进程间创建一对互相连接的socket(通常为UNIX域套接字)。这两个socket形成了一个全双工的通信通道,允许数据在两个进程之间双向传递。这常用于父进程与子进程间的轻量级通信,或者同一应用程序内的线程间通信。

socket是一种c/s模型,需要客户端与服务端进行连接,连接还需要知道服务端的ipunix socket就是对应的unix的路径。连接后当然也完全可以实现服务端和客户端的双向通信,这种情况一般比较适合于很多个客户端对应一个服务的情况。但是如果说本身就只是单独2个进程进行相互通信的需求socketpair这个东西出现就显示更加简单一些,不要有客户端和服务端进行connect过程,也没有服务端的一个ip和unix socket路径的概念,它完全是匿名的,在创建socketpair初就已经确定了对应的2个socket的fd,两端直接与对应fd读写既可以。

或者简单的说,系统帮你生成了客户端和服务端,直接使用就可以了。但是这里是有限制的

  1. 创建两个套接字:socketpair() 不像普通的 socket() 函数那样只创建一个套接字,而是创建一对套接字。这两个套接字被设计为只能与对方通信,不能与其他任何套接字通信。
  2. 连接这两个套接字:创建的两个套接字会被自动连接在一起,形成一个双向通信通道。这意味着你可以在其中一个套接字上发送数据,然后在另一个套接字上接收数据,反之亦然。
  3. 返回描述符:socketpair() 函数返回两个文件描述符,分别对应创建的两个套接字。你可以使用这两个描述符在进程或线程之间传递数据。