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 表示数据只能由服务端流向客户端。(表现为服务端收到的参数是空对象,并且服务端修改对象后客户端会同步变动)
-
inoutinout则表示数据可在服务端与客户端之间双向流通。(表现为服务端能接收到客户端传来的完整对象,并且服务端修改对象后客户端会同步变动)
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模型,需要客户端与服务端进行连接,连接还需要知道服务端的ip,unix socket就是对应的unix的路径。连接后当然也完全可以实现服务端和客户端的双向通信,这种情况一般比较适合于很多个客户端对应一个服务的情况。但是如果说本身就只是单独2个进程进行相互通信的需求socketpair这个东西出现就显示更加简单一些,不要有客户端和服务端进行connect过程,也没有服务端的一个ip和unix socket路径的概念,它完全是匿名的,在创建socketpair初就已经确定了对应的2个socket的fd,两端直接与对应fd读写既可以。
或者简单的说,系统帮你生成了客户端和服务端,直接使用就可以了。但是这里是有限制的
- 创建两个套接字:
socketpair()不像普通的socket()函数那样只创建一个套接字,而是创建一对套接字。这两个套接字被设计为只能与对方通信,不能与其他任何套接字通信。 - 连接这两个套接字:创建的两个套接字会被自动连接在一起,形成一个双向通信通道。这意味着你可以在其中一个套接字上发送数据,然后在另一个套接字上接收数据,反之亦然。
- 返回描述符:
socketpair()函数返回两个文件描述符,分别对应创建的两个套接字。你可以使用这两个描述符在进程或线程之间传递数据。