谈谈Mac进程间通信--XPC

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了谈谈Mac进程间通信--XPC相关的知识,希望对你有一定的参考价值。

参考技术A XPC Service 是一种整合了 GCD 与 launchd 的一种轻量级进程间通信机制,其主要目的是提供:权限分离和稳定性。

XPC Service由 launchd 来管理其启动、监视及终止,比如崩溃恢复,服务完成或者闲置会被 kill -9 终止,更好地管理XPC服务的生命周期。

通过 find /System/Library/Frameworks -name \*.xpc 或者 find /Applications -name \*.xpc 搜索系统框架及应用下的 XPC 服务,可以发现: XPC 被广泛使用在系统框架、系统应用及第三方应用中,如 Xcode 、 Chrome 、 CleanMyMac 等。不过对于 ios ,只能苹果使用对于第三方开发者无法使用(xcode中也未提供相应的模版)。

苹果提供了两种处理xpc服务端api:

下面将介绍下典型的使用上述接口来创建使用 XPC 服务。

XPC 服务典型应用就是应用内组件之间通信以实现权限分离保证核心功能稳定性,其创建相对简单,xcode已经提供了相应的模版,编译后会直接添加到相应的应用包中,路径为 /Contens/XPCSercices ,其包结构与应用包结构类似,都包含二进制程序、 Info.plist 文件及添加的资源文件;

xcode创建服务模版默认使用 NSXPCConnection 方式, Info.plist 中配置的 XPCService 字典服务类型 ServiceType 为 Application , Info.plist 还包含其他定义服务属性及类型字段,如下:

创建服务并监听连接典型使用如下:

由 xpc_main 函数来启动服务并设置事件处理函数,其中事件处理函数 XPCService_event_handler 主要设置事件连接处理函数并 xpc_connection_resume 恢复连接;默认连接处理队列是 DISPATCH_TARGET_QUEUE_DEFAULT ,可以通过 xpc_connection_set_target_queue 修改 GCD 处理队列; xpc_connect 提供了同步或者异步的发送/接收消息接口,如下:

其中 xpc_connection_send_message_with_reply_sync 为同步接口,阻塞直到收到应答消息,其余为异步接口; xpc_connection_send_barrier 可以设定最后一条消息发送完成后的执行 block ,类似 dispatch 栅栏接口。

消息发送实现如图:

其实质是通过 mach_msg 发送消息,即通过 mach 消息机制实现;

基于 Objective-c 形式如下:

NSXPCConnection 相关的类提供更为高级的接口,通过 NSXPCListener 来监听服务连接,并通过指定 NSXPCListenerDelegate 代理方法 listener:shouldAcceptNewConnection: 来处理新的连接请求; NSXPCConnection 属性 exportedInterface 及 exportedObject 来指定导出接口(通过协议实现)及对象,用于对端服务进程分别通过指定的 NSXPCConnection 属性 remoteObjectInterface 及 remoteObjectProxy 来获取远端约定的导出接口及导出对象,进而实现本地调用远端方法,即远程过程调用;

典型使用接口如下:

主要的流程如下:

对于创建的 xpc_connection_t 连接对象可通过全局对象保存,用于后续消息同一连接消息发送/接收;

典型使用如下:

大致的流程如下图;

通过 initWithServiceName 来创建 NSXPCConnection 连接对象, interfaceWithProtocol 来指定约定的协议方法, resume 来启动连接;当通过 remoteObjectProxy 对象来调用xpc服务的方法时, launchd 会搜索应用包中匹配的xpc服务并启动该服务,通过创建xpc服务的代理方法来接口连接,并执行导出接口方法。

相比其他的进程间通信方式,如 NSDistributedNotificationCenter 、 Mach Port 、域套接字等, XPC 服务实现更轻量,无需管理子进程的生命周期,并且能实现子进程崩溃恢复功能,通过 NSXPCConnection 相关的高级接口方便实现远程过程调用,使用更为简洁易用;

XPC

XPC介绍

XPC API

Creating XPC Services

Daemons and Services Programming Guide

Introducing XPC

利用XPC实现多进程之间的通信

《深入理解MacOS X &iOS操作系统》

进程间通信 (OSX/iOS)

在 Mac OS X 上进行进程间通信的最佳方式

【中文标题】在 Mac OS X 上进行进程间通信的最佳方式【英文标题】:Best way to do interprocess communication on Mac OS X 【发布时间】:2010-05-17 02:22:01 【问题描述】:

我正在考虑在 Mac 上构建一个带有后端守护进程的 Cocoa 应用程序(实际上可能只是一个大部分无头的 Cocoa 应用程序),以及在本地运行的 0 个或多个“客户端”应用程序(尽管如果可能的话)我也想支持远程客户端;远程客户端只能是其他 Mac 或 iPhone OS 设备。

所传递的数据将是相当微不足道的,主要是文本和命令(我猜无论如何都可以表示为文本),也许偶尔会有小文件(可能是图像)。

我已经查看了一些方法来执行此操作,但我不确定哪种方法最适合手头的任务。我考虑过的事情:

读取和写入文件(……是的),非常基本但不是很可扩展。 纯套接字(我没有使用套接字的经验,但我似乎认为我可以使用它们在本地和通过网络发送数据。虽然如果在 Cocoa 中做所有事情似乎很麻烦 分布式对象:对于这样的任务似乎相当不优雅 NSConnection:我真的不知道这个类是做什么的,但我在一些 IPC 搜索结果中读到了它

我确定我缺少一些东西,但我很惊讶地发现缺乏关于这个主题的资源。

【问题讨论】:

【参考方案1】:

我目前正在研究同样的问题。对我来说,以后添加 Windows 客户端的可能性会使情况变得更加复杂。在你的情况下,答案似乎更简单。

关于您考虑过的选项:

    控制文件:虽然可以通过控制文件进行通信,但您必须记住,文件需要通过网络文件系统在相关机器之间进行通信。因此,网络文件系统充当实际网络基础设施的抽象,但不提供网络通常具有的全部功能和灵活性。 实现: 实际上,每对客户端/服务器至少需要两个文件:服务器用于向客户端发送请求的文件和用于响应的文件。如果每个进程都可以双向通信,则需要复制它。此外,客户端和服务器都在“拉”的基础上工作,即他们需要经常重新访问控制文件,看看是否有新的东西已经交付。

    此解决方案的优势在于它最大限度地减少了学习新技术的需要。最大的缺点是对程序逻辑的要求很高;很多事情需要你处理(文件会写成一个文件,还是会发生任何一方拾取不一致的文件?应该多久执行一次检查?我需要担心文件系统,比如缓存等?我可以稍后添加加密而不玩弄我的程序代码之外的东西吗?...)

    如果可移植性是一个问题(据我从您的问题中了解到的情况并非如此),那么此解决方案将很容易移植到不同的系统甚至不同的编程语言。但是,我不知道任何适用于 iPhone OS 的网络文件系统,但我对此并不熟悉。

    Sockets:编程接口肯定不一样;根据您对套接字编程的经验,这可能意味着您有更多的工作要先学习它,然后再调试它。 实现:实际上,您将需要与以前类似的逻辑,即客户端和服务器通过网络进行通信。这种方法的一个明确优点是进程可以在“推送”的基础上工作,即它们可以在套接字上侦听直到消息到达,这优于定期检查控制文件。网络损坏和不一致也不是您关心的问题。此外,您(可能)对建立连接的方式拥有更多控制权,而不是依赖程序无法控制的事物(同样,如果您决定稍后添加加密,这很重要)。

    优点是您无需承担很多会影响 1 中的实现的事情。缺点是您仍然需要大幅更改程序逻辑以确保发送和接收正确的信息(文件类型等)。

    根据我的经验,可移植性(即易于转换到不同的系统甚至编程语言)非常好,因为任何与 POSIX 远程兼容的东西都可以工作。

    [编辑: 特别是,一旦你传达二进制数字节序成为一个问题,你必须手动处理这个问题 - 这是一个常见的(!)特殊情况“正确的信息”我上面提到的问题。它会咬你,例如当您有一台 PowerPC 与一台 Intel Mac 通话时。这种特殊情况在解 3.+4 中消失。将所有其他“正确信息”问题放在一起。]

    +4。 分布式对象:NSProxy类集群用于实现分布式对象。 NSConnection 负责建立远程连接作为发送信息的前提,所以一旦你了解了如何使用这个系统,你也就了解了分布式对象。 ;^)

    这个想法是您的高级程序逻辑不需要更改(即,您的对象通过消息进行通信并接收结果,并且消息以及返回类型与您在本地实现中习惯的相同) 而不必担心网络基础设施的细节。好吧,至少在理论上。 实施:我现在也在做这个,所以我的理解仍然有限。据我了解,您确实需要设置某种结构,即,您仍然必须决定哪些进程(本地和/或远程)可以接收哪些消息;这就是NSConnection 所做的。此时,您隐式定义了客户端/服务器架构,但您无需担心2中提到的问题。

    在 Gnustep 项目服务器上有一个带有两个显式示例的介绍;它说明了该技术的工作原理,并且是一个很好的实验起点: http://www.gnustep.org/resources/documentation/Developer/Base/ProgrammingManual/manual_7.html

    不幸的是,缺点是完全失去了与其他系统的兼容性(尽管您仍然可以使用您提到的 Mac 和 iPhone/iPad 的设置)以及失去对其他语言的可移植性。带有 Objective-C 的 Gnustep 充其量是代码兼容的,但没有办法在 Gnustep 和 Cocoa 之间进行通信,请在此处查看我对问题 2 的编辑:CORBA on Mac OS X (Cocoa)

    [编辑:我刚刚发现了另一条我不知道的信息。虽然我检查了NSProxy 在 iPhone 上可用,但我没有检查分布式对象机制的其他部分是否可用。根据此链接:http://www.cocoabuilder.com/archive/cocoa/224358-big-picture-relationships-between-nsconnection-nsinputstream-nsoutputstream-etc.html(在页面上搜索短语“iPhone OS”)它们不是。如果您此时需要使用 iPhone/iPad,这将排除此解决方案。]

因此,总而言之,一方面是学习(以及实施和调试)新技术的努力,另一方面是手动编码较低级别的通信逻辑。虽然分布式对象方法承担了您的大部分负担,并在程序逻辑中产生了最小的变化,但它是最难学习的,而且(不幸的是)最不便携。

【讨论】:

虽然 DO 确实缺乏可移植性,但我很好奇为什么你觉得它们最难学习?在我看来,可移植的低级解决方案要困难得多,因为您必须自己处理更多层(连接处理、编组......)。 iPhone 上的 DO,遗憾的是它看起来像 you're right。我没注意到,这很烦人。 @Georg Fritzsche:这可能更多是由于我的学习(不)能力而不是 DO;但我过去使用过传统的消息传递系统 (MPI) 和套接字编程,这可能会导致我的感知偏差。我发现很容易弄清楚如何进行数据通信,并且不用担心远程方法调用。 DO 迫使我还考虑除了数据之外的远程方法,这使得这种方法对我来说更加复杂和不直观。 我想,一旦建立连接,通常的面向数据的通信会突然透明地发生,我想可能需要习惯。 :) (旁注:comment notifications 不需要全名) @Georg:一旦涉及到调试,就需要弄清楚一条数据来自哪里以及为什么它看起来像这样。远程和分布式调试绝非易事;不同的语法在这里既无帮助也无害。在 DO 的情况下,多一层抽象和远程方法会引入更多复杂性。也许那些自然而然地思考的人(或者不需要调试她的程序的人;^)不会发现它比面向数据的通信更难,但对我来说它更复杂。【参考方案2】:

免责声明:分布式对象是not available on iPhone。


为什么你觉得distributed objects 不优雅?他们在这里听起来很合适:

基本类型和 Objective-C 类的透明编组 客户端是本地还是远程并不重要 对于基于 Cocoa 的应用程序没有太多额外的工作

文档听起来可能比实际工作更多,但您基本上要做的就是干净地使用协议并导出或分别连接到服务器根对象。 其余的应该在给定的场景中自动在幕后为您发生。

【讨论】:

+1 这确实是分布式对象旨在解决的问题。 @jbr:为什么,为您完成工作不是一件好事吗?链接的文档也很好地解释了我认为的机制。 我对 DO 的厌恶源于它对异常的广泛使用……感觉不自然。 称我为老式的,但我总是对添加几层精细“自动”以假装远程活动和本地活动之间没有区别的技术有点怀疑。 (EJB,我在看着你。还有 CORBA。还有 DCOM。甚至是 olde worlde RMI。)也许有一天世界会被一个连续的进程空间所包围,但在那之前这里 和 there 不是一回事,记住这一点也不错。 @walkytalky 你太老土了:)。【参考方案3】:

我们正在使用ThoMoNetworking,它运行良好且设置速度很快。基本上,它允许您在本地网络中发送符合 NSCoding 的对象,但如果客户端和服务器在同一台机器上,它当然也可以工作。作为基础类的包装器,它负责配对、重新连接等。

【讨论】:

以上是关于谈谈Mac进程间通信--XPC的主要内容,如果未能解决你的问题,请参考以下文章

进程间通信

从AILD与bindService谈Binder进程间通信原理(上)

从AILD与bindService谈Binder进程间通信原理(上)

对于 Mac 上的高带宽数据流,最有效的进程间通信方法是啥?

在 Mac OS X 上进行进程间通信的最佳方式

Mac OS X Lion 上的进程间通信