Qt Remote Objects 动态Replica

        上一篇QtRO的文章(Qt Remote Objects 静态Replica)中我们介绍了它的静态用法,并给出了一个具体例子。这篇文章我给大家介绍动态Replica,即Dynamic Replica。

Server端变化

        要支持动态Replica,Server端其实不需要做太大更改,主要流程和静态Replica一致。但需要注意:

       在定义rep接口文件时,禁用POD。换句话说,所有的数据类型必须是基本类型(即float、int等基本C++类型,还有QString、QPoint等基本Qt类型)。QtRO中的POD类型依赖于QDataStream的序列化和反序列化,这些都需要Qt元信息的支持。而动态Replica那边没有了rep文件,也就没有了对POD的反序列化能力,换句话说就是它不认识收到的POD二进制数据了。

        如果Server端确实需要传输复杂的数据类型(这个在接口复杂的时候是个刚需),那我建议用QVariantListQVariantMap来定义。虽然传输性能上差一些,但是在提供更好的数据封装的情况下仍然保持了好的QtRO编程习惯。

        所以,现在我们的TransferNews例子的Server端唯一改变的是在transfernews.cpp中的注释掉下面这行代码:

//emit testPod(Foo(list));

        Source端算是准备好了。

Replica端变化

        采用动态方式的话,Replica端变化相对较多。

        首先是pro文件中不再需要引入rep文件。所以去掉下面这行代码:

REPC_REPLICA = transfernews.rep

        然后在获得Replica的时候,需要用动态的版本:

 ptr.reset(repNode.acquireDynamic("TransferNews"));

        此时,如果我们运行Replica端程序,会发现下面的错误:

QObject::connect: No such signal QRemoteObjectReplica::lastMessageChanged(QString)
QObject::connect: No such signal QRemoteObjectReplica::serverTime(QString)

        这是因为我们在dynamicconnect.cpp里将replica的信号连接到本地的槽函数上,而此时动态replica其实还未初始化好,也就是说它根本没有这些信号。这就引出动态Replica的一个重要特点:

        只有当Replica发出initialized信号后,该Replica才有Server端的元信息(属性、信号与槽),才能被使用。

        仔细想想就能明白为什么。因为没了rep文件,程序刚启动时怎么可能知道你要连接的Server端长啥样。所以动态Replica的内部原理是建立连接后,首先获得Server端的元信息,然后动态地在Replica端构建属性、信号和槽。这些构造完毕后,Replica会发送一个initialized的信号,这之后该Replica才能够真正被使用。

        所以,我们要确保的就是只有Replica初始化好了我们才在widget中使用该Replica进行信号绑定等操作。解决方法也很简单,在dynamicconnect.cpp中用下面的代码来绑定:

QObject::connect(ptr.data(), SIGNAL(initialized()), this, SLOT(initConnection()));

void DynamicConnect::initConnection()
{
    QObject::connect(m_ptr.data(), SIGNAL(lastMessageChanged(QString)), this, SLOT(slot_lastMessageChanged(QString)));
    QObject::connect(m_ptr.data(), SIGNAL(serverTime(QString)), this, SLOT(slot_serverTimeChanged(QString)));
}

        再运行Replica端程序,发现上面的错误消失了,运行结果和之前的静态方式一致。

        当然,上面的代码应该是最简单的形式。

静态 Vs. 动态

  • 静态方式的优劣:
    • pros:
      • 拥有明确的定义,更适合在C++中使用(因为有repc生成的头文件)。
      • 支持POD等复杂结构的定义。
      • 更高效。因为结构定义都已经在C++中定义好了,不需要动态传输、构建,省去了这方面的开销(其实不大,但多少是有开销的)。
    • cons:
      • Source端和Replica端必须严格使用同一版本的rep文件,即使rep文件内只是添加了一行注释,否则连接不上。
  • 动态方式的优劣:
    • pros:
      • Source端和Replica端不再需要严格使用同一版本的rep文件,因为Replica端已经不需要该文件了,所以Source端随时更改(当然不能改接口定义,不然Replica端肯定没法调用)。
      • Source端可以对接口进行版本管理,在兼容旧接口的情况下,动态Replica不需要做任何更新。这个其实是和上面这条联系在一起的。
    • cons:
      • 不支持POD等复杂结构定义。但可以用QVariantListQVariantMap两兄弟来曲线救国。
      • 必须等初始化后才能使用,给编程增加了额外复杂度,同时增加了构建连接的额外开销。这个是动态这个特性决定的。

相信看了这个比较后,应该知道怎么选择了吧?

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值