自Qt 5.9之后,Qt推出了一个框架库,Qt称作Qt Remote Objects(QtRO),我自己翻译为远端可调用对象哈哈,不像其他的Qt功能库,这个是没有示例工程的,只有一个在帮助手册overview里面的三个例子,那么先说明Qt的RO是什么

首先,进程通信一般分为 消息队列,共享内存,管道(有名和无名),TCP/UDP等,也就是IPC的绝大多数机制,当然TCP和UDP可以具有RPC的机制,如果你要写的话;

传统的进程通信已经无法满足分布式等跨越机器网络的函数调用、耦合度降低、可扩展等情况,那么就需要一些可以复用的框架扩展,于是出现了COM通信调用,ICE框架等,但是使用这些框架有问题在于平台的兼容问题;那么问题来了,如果自己拿Qt的原有框架写要怎么写一个呢,我想大家无非就是想QT现在做的一样,自己搞一个映射吧

那么可以猜测我们要这样子写

1、建立通信 :TCP或者管道,建立客户端和服务

2、定义模板,需要公布对外的函数,对象,使用字符串发布到服务,或者协议内

3、建立自身的函数接口映射,当服务器发送消息的时候调用对应的函数和参数

4、管理自身的连接

以上几部只是大概的按照工作经验猜测Qt的RO逻辑,实际上也差不多,那么可想而知,Qt的qml通信,QT和web的包裹通信也是应该是使用这个机制,研究这个机制,也就很容易了解了其他几个的机制,在编写代码的时候,也会很清楚写的意义,好了,下面我们开始学习QT的示例代码

例子1 单机静态编码直连

qt 连接MongoDB qt remote object_qt 连接MongoDB

帮助手册翻译

1.第一步,创建一个Rep文件(但是我个人觉的还是先创建一个控制台工程,再添加该文件)

qt 连接MongoDB qt remote object_IPC_02

QT示例代码如上

该文件作用是一个模版,用于后面由Qt目录下面的repc编译生成对应的一些代码,有点像信号与槽,之后生moc文件或者ui生成xxx_ui.h文件

PROP是在手册里面有说明,表示是一个属性,QT元对象系统里面对应会生成QProperty声明,qml也是类似,声明作用在于会生成对应的读写、信号等函数操作,而且都可以对外调用

类似的宏可以看Qt手册里面的解释

SLOT就不用说了,是声明一个槽函数

2.添加到工程中(这个也就是为什么我说最好先创建工程的原因)

qt 连接MongoDB qt remote object_RPC_03

在工程文件目录下添加该文件,并且把该文件声明到.pro文件中

我的文件名称自己改了

qt 连接MongoDB qt remote object_qt 连接MongoDB_04

REPC_SOURCE的作用在于,告知qmake,这个是一个rep的资源文件,后面需要调用repc去编译生成一个头文件

需要注意的是 QT += remoteobjects需要先添加,否则没办法识别出来

添加完成之后可以试着编译一下,正常情况下会在生成目录下生成一个头文件,该头文件

qt 连接MongoDB qt remote object_RPC_05

该头文件大致是这样子,个人称作为模版源文件

该文件用来干什么呢,其实就是之前说的,里面有三个类

一个实现了函数的映射,一堆的映射,正常人都可以完成,所以Qt帮我们完成了

一个是接口类,后面用于实现继承,当然QT已经帮我们实例化继承了,这个纯虚类,主要是对外的接口解耦使用

一个是实例化上面接口的类,他实现了之前定义了模板的函数和属性,我们要使用的就是这个类型,好像会自动添加一个simple字符

3. 实现模板编译出来的类型(注意需要qmake编译一下)

在生成了xxx_source.h文件之后,编写一个新的类型

qt 连接MongoDB qt remote object_IPC_06

继承类型如上,来自repc编译生成的头文件中的类

需要说明的是,之前模板中的server_slot函数默认是没有做事情的,所以需要重写,然后才能使用,记得使用virtual,否侧调用会不正常,这个是虚函数的知识,具体可以自行搜索

其他的都是一堆测试的函数,里面搞了一个计时器,在自己初始化的时候开始修改自己的状态,也就是模版里面定义,在repc编译后生成属性和对应的函数 current

qt 连接MongoDB qt remote object_Qt_07

红色的函数就是由于repc编译生成的函数,继承后继续使用

至此,我们的工作完成了一大半,该调用测试一下

qt 连接MongoDB qt remote object_RPC_08

代码还是来自Qt的示例,修改了一点点

说明:创建了client之后其实就开始调用状态修改了,后面的代码对于单程序测试没有用,但是要在这里说明,因为下面两个程序一起执行的时候这个意义就有了

首先创建了一个host,看这个是一个字符串,表示本地连接,关键词test,这个猜测QT内部可能使用了下面这个qt的类

qt 连接MongoDB qt remote object_qt 连接MongoDB_09

该类型是一个本地程序通信的类,需要一个关键词识别连接

 

编译执行程序效果如下:

qt 连接MongoDB qt remote object_RPC_10

这个程序很简单,就算写一个简单的类也可以,但是这个用于后面

4.新建客户端工程

把上一个工程里面的那个模板rep文件复制或者引用添加到当前工程,然后在工程中添加

qt 连接MongoDB qt remote object_Qt_11

完成之后应该是上面的样子,编译测试一下,会在工程的生成目录下生成一个xxx_replic.h文件,称作可调用对象,也就是客户代理对象

qt 连接MongoDB qt remote object_qt 连接MongoDB_12

 

该对象都已经按照模板实现了所有的函数

 

5.编写调用该代理类型

qt 连接MongoDB qt remote object_qt 连接MongoDB_13

按照示例代码,重点是初始化里面,和代理对象进行了连接

 

完成了上述代码,之后就是使用该类

qt 连接MongoDB qt remote object_qt 连接MongoDB_14

 

在main中实现使用该对象,其中第一步是创建客户端,连接,关键词和之前创建的程序必须相同

第二步是创建代理对象,也就是该对象会和最先创造的程序连接

之后创建客户端类,主要工程就是信号槽连接,在发生变化的时候打印出来而已

至此,一个本地的RO就连接好了,运行两个程序

qt 连接MongoDB qt remote object_Ro_15

效果如上,也就是说,第一个程序建立了服务,把代理对象注册到网络,允许其他人知道他的存在和调用

第二个程序连接服务,被告知,你可以使用的程序如上,之后他的状态变化了也就被第二个程序知道了,那么这个学习也算是告一段落,如果需要跨越pc,其实是类似的

Qt给的第二个例子,使用的动态调用,方法很像qml动态注册之后动态写入属性的办法,动态调用的意义在于不需要repc编译客户端rep文件,而是直接写代码调用即可

步骤如下:

1.之前例子中的服务端的代码不变,编译就好

2.修改上述例子中的代码

qt 连接MongoDB qt remote object_IPC_16

针对代理类client修改为Qt的默认类型,这个类型也是repc编译生成的类型使用的基类

qt 连接MongoDB qt remote object_IPC_17

 

在main中修改调用方法,动态的获取,按照之前服务端rep的名称获取

qt 连接MongoDB qt remote object_RPC_18

名称可以参考服务端自动生成的文件上面标注地方

编译两个程序执行

qt 连接MongoDB qt remote object_qt 连接MongoDB_19

生成结果一样,除了警告

 

如果需要使用网络,则只需要修改地址即可:

1.修改main代码

qt 连接MongoDB qt remote object_Ro_20

左侧为客户端代码,右侧为服务端代码

按照QT例子需要注册,但是实际上好像去掉也可以连接

运行程序,虚拟机里面IP是192.168.104 建立服务端

物理机ip是103

运行结果

qt 连接MongoDB qt remote object_qt 连接MongoDB_21

qt 连接MongoDB qt remote object_Qt_22

看来Qt有些东西也是理解不清楚,感觉注册不需要

经过多种测试,应该是这样子使用注册地址

qt 连接MongoDB qt remote object_RPC_23

也就是说,只有两边都使用注册的时候,连接会自动连接上

另外,关于Qt的网络连接的使用,QT还提供了额外的玩法

qt 连接MongoDB qt remote object_Qt_24

就像帮助手册里面的一样,可以提供对TCP的控制,那么也就是可以使用多线程操作我们需要的tcp,如果有必要的话