概述

前一篇文章我们介绍了QtRO静态Replica来实现进程间通信的基本用法,本文接着介绍QtRO的另一个部分,动态Replica,也就是Dynamic Replica。

QtRO本身是包含两种方式的,一个是静态,一个是动态,这两者实现方式稍有区别,其对应的场景也有所不同。

上一篇文章我们说到,要实现QtRO最重要的一步是创建rep文件,通过在rep文件中定义公共接口从而进行共享,而静态和动态Replica的最大的区别就在于,静态Replica比如在server和client端都需要一个相同的rep文件作为接口定义,而动态是指Client这边不再需要rep文件,而是运行时动态获取接口定义。

静态和动态的对比

既然支持这两种方式,那么该如何选择使用呢?接下来看看二者的优劣:

静态Replica:

优势

  • 拥有明确的定义,更适合在C++中使用(因为有repc生成的头文件)。
  • 支持POD等复杂结构的定义。
  • 更高效。因为结构定义都已经在C++中定义好了,不需要动态传输、构建,节省了开销。

劣势

  • Source端和Replica端必须严格使用同一版本的rep文件,即使rep文件内只是添加了一行注释,否则会连接不上。

动态Replica:

优势

  • 由于Client端不需要rep文件,所以Server端可以随时修改,这就避免了静态模式下的缺点。

劣势

  • 不支持POD等复杂结构定义。
  • 必须等初始化后才能使用,给编程增加了额外复杂度,同时增加了构建连接的额外开销。这个是动态这个特性决定的。

POD类类型

上面提到POD类型,简单的介绍一下。
POD类类型就是指class、struct、union,且不具有用户定义的构造函数、析构函数、拷贝算子、赋值算子;不具有继承关系,因此没有基类;不具有虚函数,所以就没有虚表;非静态数据成员没有私有或保护属性的、没有引用类型的、没有非POD类类型的(即嵌套类都必须是POD)、没有指针到成员类型的(因为这个类型内含了this指针)

简单的理解就是,POD即float、int等基本C++类型,还有QString、QPoint等基本Qt类型。而静态Replica支持POD类型,动态Replica不支持POD类型。

示例

接下来我们在上一篇文章的代码基础上进行修改,改成动态Replica的模式。

Server端变化

要支持动态Replica,Server端不需要做太大的改变,只有两点需要注意:

  • 上面我们提到动态Replica不支持POD类型,因为QPOD类型依赖于QDataStream的序列化和反序列化,这些都需要Qt元信息的支持。而动态Replica那边没有了rep文件,也就没有了对POD的反序列化能力,换句话说就是它不认识收到的POD二进制数据了。所以如果一定要使用POD类型的话,可以使用QVariantList和QVariantMap来定义。
  • Server 端enableRemoting时必须传入第二个参数name,因为没有了类型,动态Replica端不知道该链接那个Server端,所以只能通过name来区分

综上,需要修改的是:

m_pHost->enableRemoting(m_pInterface,QStringLiteral("Interfaces1"));

Client端变化

动态Replica模式下,Client端不需要rep文件,所以在pro文件中,直接去掉:

#REPC_REPLICA += \
#    ../Reps/CommonInterface.rep

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

m_pInterface = m_pRemoteNode->acquireDynamic("Interfaces1");//动态获取

这里的"Interfaces1"就是在Server端的名字。

此外,还有一个关键的点需要改动,因为没了rep文件,程序刚启动时不知道连接的Server端长啥样。所以动态Replica的内部原理是建立连接后,首先获得Source端的元信息,然后动态地在Replica端构建属性、信号和槽。这些构造完毕后,Replica会发送一个initialized的信号,这之后该Replica才能够真正被使用。

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

改动如下:

//只有Replica初始化好了才能真正使用它,要不然connect无效connect(m_pInterface, &QRemoteObjectDynamicReplica::initialized, this, &MainWidget::onInitConnect);...void MainWidget::onInitConnect()
{connect(m_pInterface,SIGNAL(sigMessage(QString)),this,SLOT(onReceiveMsg(QString)));connect(this,SIGNAL(sigSendMsg(QString)),m_pInterface,SLOT(onMessage(QString)));
}

OK,改动已完成。

我们看一下Client端完整的代码:

#ifndef MAINWIDGET_H
#define MAINWIDGET_H#include <QWidget>
#include <QRemoteObjectNode>
//#include "rep_CommonInterface_replica.h"
#include <QRemoteObjectDynamicReplica>namespace Ui {
class MainWidget;
}class MainWidget : public QWidget
{Q_OBJECTpublic:explicit MainWidget(QWidget *parent = nullptr);~MainWidget();
signals:void sigSendMsg(QString msg);
private slots:void onReceiveMsg(QString msg);void on_pushButton_clicked();void on_lineEdit_returnPressed();void onInitConnect();private:void init();
private:Ui::MainWidget *ui;QRemoteObjectNode * m_pRemoteNode = nullptr;QRemoteObjectDynamicReplica * m_pInterface = nullptr;
};#endif // MAINWIDGET_H

mainwindow.cpp

#include "mainwidget.h"
#include "ui_mainwidget.h"MainWidget::MainWidget(QWidget *parent) :QWidget(parent),ui(new Ui::MainWidget)
{ui->setupUi(this);this->setWindowTitle("This is Client");init();ui->textEdit->setReadOnly(true);
}MainWidget::~MainWidget()
{delete ui;
}void MainWidget::init()
{m_pRemoteNode = new QRemoteObjectNode(this);m_pRemoteNode->connectToNode(QUrl("local:interfaces"));
//    m_pInterface = m_pRemoteNode->acquire<CommonInterfaceReplica>();m_pInterface = m_pRemoteNode->acquireDynamic("Interfaces1");//动态获取//只有Replica初始化好了才能真正使用它,要不然connect无效connect(m_pInterface, &QRemoteObjectDynamicReplica::initialized, this, &MainWidget::onInitConnect);
}/*** @brief MainWidget::onReceiveMsg* @param msg* 接收服务器下发的消息*/
void MainWidget::onReceiveMsg(QString msg)
{ui->textEdit->append(QString("Server:") + msg);
}void MainWidget::on_pushButton_clicked()
{QString msg = ui->lineEdit->text();if(!msg.isEmpty()){
//        m_pInterface->onMessage(msg); //调用槽发送消息给服务器emit sigSendMsg(msg);}ui->textEdit->append(QString("Client:") + msg);ui->lineEdit->clear();
}void MainWidget::on_lineEdit_returnPressed()
{on_pushButton_clicked();
}void MainWidget::onInitConnect()
{connect(m_pInterface,SIGNAL(sigMessage(QString)),this,SLOT(onReceiveMsg(QString)));connect(this,SIGNAL(sigSendMsg(QString)),m_pInterface,SLOT(onMessage(QString)));}

OK,Server端只需要改动一行代码,所以就不列出来了。

注意,在静态Replica中,我们从Client发送消息给Server端时,直接调用rep文件中定义的槽onMessage就可以了,但是在动态Replica时不能直接调用了,会报错找不到这个槽,所以改成连接信号槽的方式,如下:

    if(!msg.isEmpty()){
//        m_pInterface->onMessage(msg); //调用槽发送消息给服务器emit sigSendMsg(msg);}
...connect(this,SIGNAL(sigSendMsg(QString)),m_pInterface,SLOT(onMessage(QString)));

以上,运行结果和静态Replica一样,详见上一篇文章介绍。

上述代码在这里

参考文章:
https://doc.qt.io/qt-5/qtremoteobjects-index.html
https://zhuanlan.zhihu.com/p/37108172

Qt Remote Object(QtRO)动态Replica实现进程间通信相关推荐

  1. Qt Remote Object(QtRO)实现进程间通信

    概述 Qt Remote Object简称QtRO,这是Qt5.9以后官方推出来的新模块,专门用于进程间通信(IPC).在这之前,要实现进程间通信有多种方式,这里就不做介绍了,而Qt官方推出的这个新模 ...

  2. Qt Remote Object(QtRO)给指定的客户端发送消息

    概述 前面写了两篇文章介绍QtRO的使用方法,在这里: Qt Remote Object(QtRO)实现进程间通信 Qt Remote Object(QtRO)动态Replica实现进程间通信 然后会 ...

  3. Weblogic - Failed to bind remote object 错误解决方法

    环境 Solaris 10 Enterprise Weblogic 9.2.1.0 一.错误解决 今天上午,QA测试一同事的应用时,在建立JDBC连接池并绑定到JNDI时出错,弄了许久,同事和QA都没 ...

  4. 使用uiaotumator viewer 时报错 Remote object doesn't exist!

    使用uiaotumator viewer 时报错 Remote object doesn't exist! Error while obtaining UI hierarchy XML file: c ...

  5. C++将带ui界面的qt工程封装为动态库dll

    C++将带ui界面的qt工程封装为动态库dll 功能如下 完整源代码实现如下 功能如下 将工程封装后可以在别的工程下直接引用该界面,以及该界面的函数, 完整源代码实现如下 #ifndef BUILD_ ...

  6. QT 静态库和动态库的使用方法

    QT 静态库和动态库的使用方法 背景知识:程序在编译成可执行文件时,会有四步过程: 1预处理(头文件和宏定义) g++ -E 1.cpp -o 1.i 2编译 将c代码编译成汇编代码 g++ -S 1 ...

  7. jstatd Could not create remote object 异常问题解决

    异常信息如下: Could not create remote object access denied ("java.util.PropertyPermission" " ...

  8. Error while obtaining UI hierarchy XML file: com.android.ddmlib.SyncException: Remote object doesn‘t

    使用uiautomatorviewer连接模拟器页面报错:Error while obtaining UI hierarchy XML file: com.android.ddmlib.SyncExc ...

  9. Qt设置运行时动态库路径的几点说明

    随着需求的不断增加,程序不断变大,用到的动态库也越来越多,到了发布程序的时候你会发现和可执行文件同一目录下文件数量真多(比如著名的金融软件 https://www.webull.com/ 哎呀我去,目 ...

最新文章

  1. new和malloc的区别
  2. Java开发知识体系!我用2个月的时间破茧成蝶
  3. spring-data-JPA使用JpaRepository注解自定义SQL查询数据库多表查询
  4. LINUX之网络编程j简述
  5. linux中 centos6 文件误删如何恢复
  6. java皮肤库的框架_VC 添加皮肤库
  7. 宅家办公不宅心,送3本技术好书
  8. 漫谈并发编程(三):共享受限资源
  9. Python变量的作用范围
  10. 【PostgreSQL-9.6.3】创建、修改、删除PostgreSQL数据库
  11. 如何零基础入门PS软件?
  12. leaflet 加载海量点位,点击marker 查看详情功能
  13. 工业以太网交换机常见的几种故障类型及分析排查方法
  14. 开发板 linux 同步时间,arm开发板使用ntp与服务器同步时间
  15. python爬取作品集_Python爬虫爬取哈利波特小说集,并用数据可视化剖析登场人物...
  16. java压_JAVA背压
  17. 【java实现定时自动发送QQ消息】
  18. 天平应什么放置_天平的使用规程
  19. 【VSCode】安装VSCode都需要配置什么?
  20. STM32WL开发之LM401评估板开箱及PingPong测试

热门文章

  1. CVPR 2019 | 目标检测之面向更高精度的包围框回归
  2. ICCV 2019 最佳论文和最佳学生论文下载
  3. Java vs Kotlin,Android开发人员应该选择哪种语言?
  4. Vue安装jquery插件
  5. https和server-status配置案例
  6. error LNK2001: 无法解析的外部符号 __imp__Shell_NotifyIconA@8
  7. 【转载】SOA面向服务架构简述
  8. Office远程代码执行漏洞补丁(905413)
  9. 重磅!!kaggle训练, 终于不用怕断网了
  10. Ubuntu21.04 Docker 安装