进程间通信简介
在许多方面,苹果的故事都是一些有趣的历史偶然事件将技术融合在一起,创造出比以前更好的东西:OS X 是 MacOS 与 NeXTSTEP 的结合。OC 是 Smalltalk 类面向对象编程与 C 的结合。iCloud 则是苹果移动服务与云平台的结合。
虽然苹果技术栈的许多方面都是如此,但是不得不说苹果技术中的进程通讯走的是“反人类”的道路。
由于不是根据每个节点上最优原则进行设计,苹果的进程间通信解决方案更显得混乱扎堆。结果是,大量重叠,不兼容的 IPC 技术在各个抽象层随处可见。(除了 GCD 还有剪贴板)
- Mach Ports
- Distributed Notifications
- Distributed Objects
- AppleEvents & AppleScript
- Pasteboard
- XPC
从低级内核抽象到高级,面向对象的 API,它们都有各自特殊的表现以及安全特性。但是基础层面来看,它们都是从不同上下文段传递或者获取数据的机制。
Distributed Objects
90 年代中 NeXT 全盛时期,分发式对象(DO)是 Cocoa 框架中一个远程消息发送特性。尽管现在已经不再大范围的使用,在现代奇数层上 IPC 无障碍通信仍然并未实现。
使用 DO 分发一个对象仅仅是搭建一个 NSConnection
并将其注册为特殊(你分的清楚)的名字:
1 | @protocol Protocol; |
另外一个应用将会也建立同样名字的并注册过的链接,然后立即获取一个原子代理当做原始对象。
1 | id proxy = [NSConnection rootProxyForConnectionWithRegisteredName:@"server" host:nil]; |
只要分发对象代理收到消息了,一个通过 NSConnection
连接远程调用(RPC)将会根据发送对象进行对应的计算并且返回结果给代理。【注:原理是一个 OS 管理的共享的 NSPortNameServer
实例对这个带着名字的连接进行管控。】
分发式对象简单,透明,健壮。简直就是 Cocoa 中的标杆。
实际上,分布式对象不能像局部对象那样使用,那就是因为任何发送给代理的消息都可能抛出异常。不想其他语言,OC 没有异常处理控制流程。所以对任何东西都进行 @try/@catch
也算是 Cocoa 大会很凄凉的补救了。
DO 还有一个原因致其使用不便。在试图通过连接 “marshal values” 时,对象和原语的差距尤为明显。
此外,连接是完全加密的,和下方通信信道扩展性的缺乏致使其在大多数的使用中通信被迫中断。
下方是左列分布式对象用来指定其属性代理行为和方法参数的注解:
- in:输入参数,后续不再引用
- out:参数被引用作为返回值
- inout:输入参数,引用作为返回值
- const:常量参数
- oneway:无障碍结果返回
- bycopy:返回对象的拷贝
- byref:返回对象的代理
XPC 通信技术
XPC 是 SDK 中最先进的进程间通信技术。它的体系结构目标是避免长时间运行的流程,适应有限的资源,并尽可能延迟初始化。将 XPC 集成到应用程序的动机不是要做原本不可能做的事情,而是要为进程间通信提供更好的特权分离和故障隔离。
它是 NSTask 的替代品,甚至不仅仅是替代品。
XPC 负责进程间通信和服务生命周期管理。从注册服务、运行服务到与其他服务通信,所有事情都由 launchd 处理。XPC 服务可以按需启动,或者在崩溃时重新启动,或者在空闲时终止。因此,服务应该设计为完全无状态,以便允许在任何执行点突然终止。
作为 iOS 采用并移植到 OS X 的新安全模型的一部分,默认情况下,XPC 服务在最严格的环境中运行:没有文件系统访问权限,没有网络访问权限,也没有 root 权限提升。任何功能都必须通过一组权利将其列入白名单。
权限问题是一大坑点😤
可以通过 libxpc C API
或 NSXPCConnection Objective-C API
访问 XPC。
XPC 服务要么驻留在应用程序包中,要么使用 launchd
命令让其在后台运行。
开启后台进程有多种方式:
- Login Items
- XPC Service
- Launch Agent
- Launch Daemons