日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2025/1/21 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Qt Remote Object(QtRO)动态Replica实现进程间通信 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

概述

前一篇文章我們介紹了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实现进程间通信的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。