QtRO是Qt RemoteObjects的简称,是从5.9开始Qt官方推出的一个用于进程间通信(IPC)的新模块。虽然该模块目前仍处于TP阶段,但已经足够稳定。由于项目开发需要,我们将一个大项目划分成了若干个子工程,各个子工程都是独立的程序,因此需要使用IPC来进行各模块间的协同工作。
QtRO优势
- Qt-like编程。由于是官方模块,QtRO使用Qt经典的信号与槽进行编程通信,独有的Source/Replica模式让远程服务调用起来就像本地的一个QObject一样,所有底层链路序列化和反序列化都由QtRO自动完成,代码维护性很高;
- 跨平台。由于是Qt官方模块,继承了“Write Once, Compile & Run Everywhere”的优良传统;
- 兼容LPC和RPC。LPC即Local Process Communication,而RPC是指Remote Process Communication,两者都属于IPC。QtRO能够工作于这两种不同的模式:如果用于LPC,则QtRO使用QLocalSocket;如果是用于RPC,则使用QTcpSocket。一样的代码,一样的逻辑。
QtRO基本结构
QtRO本质上是一个点对点的通信网络。每个进程通过QRemoteObjectNode
接入QtRO网络。功能提供节点(可以理解为服务器)需要使用QRemoteObjectHost
将一个提供实际功能的QObject
派生类注册进QtRO网络中,然后其他使用该功能的程序则通过各自的QRemoteObjectNode
连接到该Host上,然后acquire
一个该功能对象的Replica
。等到该Replica初始化好后,该程序就能够使用Replica中的信号、槽以及属性,就好像功能类就在本地一样。
QtRO程序的基本结构如下图所示:
图中功能类Source有两个Replica。当Source发生改变时,例如属性值变化、发射信号等,QtRO会通知所有Replica,从而所有客户端都将得到通知。
QtRO连接建立过程
从图中我们可以看到几个关键步骤:
- 首先服务端要把功能类通过
QRemoteObjectHost
的enableRemoting
方法共享出来; - 然后客户端要连接到该
QRemoteObjectHost
,然后acquire
到Replica; - QtRO会自动初始化该Replica,待初始化完后客户端就可以用该Replica了。
定义功能类
IPC本质上就是调用远程进程的功能。
QtRO中的功能类没什么特殊的,其实就是个QObject派生类,所以任何派生自QObject的类型都能够分享到QtRO网络中。但是为了更好地和其他模块开发者协同,推荐使用rep文件定义接口然后再实现的方式来编写功能类。
rep文件是一种DSL(Domain Specific Language),专门用于定义QtRO接口。在编译的时候,该文件会首先经过repc.exe这个程序处理,生成对应的头文件和源文件。只要安装Qt时选择了Qt RemoteObjects模块,repc.exe就在Qt安装目录的bin目录中。
由于是接口定义文件,repc在处理时就有两种方式:
- 生成用于实现功能类的头文件和源文件。此时我们将得到一个“空”的功能类,我们只需要派生自该类,然后实现所有的接口即可;
- 生成用于客户端Replica的头文件和源文件。此时我们得到的就是Replica的C++实现。我们不需要做其他操作,只需要按照上面的连接流程连接到功能类就能用了。
一份定义,两处转译,确保了Source和Replica接口一致,能够接起来,又将接口定义与实现分成了明确的两个步骤,非常适合于大型工程的开发流程。
rep文件写起来很简单,具体可以参考Qt官方文档:http://doc.qt.io/qt-5/qtremoteobjects-repc.html。