当前位置: 首页 > news >正文

QtRO(Qt Remote Objects)分布式对象远程通信

一、什么是QtRO

Qt Remote Objects(QRO)是Qt提供的一种用于实现远程对象通信的机制。
QtRO支持两种类型的通信:RPC(远程过程调用)和LPC(本地进程通信)。

RPC(远程过程调用)包括以下几种类型:
基于HTTP协议的RPC:例如Dubbo、Thrift等。
基于二进制协议的RPC:例如GRPC、Hetty等。
基于TCP协议的RPC:例如RMI、Remoting等。

LPC包括基于共享内存的通信和基于消息传递的通信。
总的来说,QtRO类似于平时的socket通信、串口通信、信号槽通信。它最大的特点是集合了这些通信的功能,使得远端通信能与本机通信一样使用信号槽的方式来收发信息

最大的优点可以说是免去了平时自己创建client端和server端时需要每次创建通信线程,解析协议,分拣数据。这里不同的数据可以直接用不同的信号槽来完成,远端通信就像是同个软件中对象之间的通信一样方便。

二、使用QtRO编写服务端

2.1首先需要编写rep文件,rep文件中包含了通信之间定义的接口。具体说明见官方文档。

以下是我的文件interface.rep

class Interface
{SIGNAL(sigMessage(QString msg))   //发送文本SIGNAL(sigPixmap(QByteArray pix)) //发送图片SIGNAL(sigFile(QByteArray data,QString fname)) //发送文件SLOT(void onMessage(QString msg)) SLOT(void onPixmap(QByteArray pix))SLOT(void onFile(QByteArray data,QString fname))
}

2.2在pro文件中添加remoteobjects模块,添加rep文件

QT += remoteobjects
REPC_SOURCE += \interface.rep

2.3构建一次工程,在输出目录会找到rep_interface_source.h文件,把它复制到工程目录。在工程中新建一个CommonInterface类:

commoninterface.h

#ifndef COMMONINTERFACE_H
#define COMMONINTERFACE_H#include "rep_interface_source.h"
class CommonInterface : public CommonInterfaceSource
{Q_OBJECT
public:explicit CommonInterface(QObject *parent = nullptr);virtual void onMessage(QString msg) override;virtual void onPixmap(QByteArray pix) override;virtual void onFile(QByteArray data,QString fname) override;void sendMsg(const QString &msg);void sendPixmap(QByteArray pix);void sendFile(QByteArray data,QString fname);signals:void sigReceiveMsg(const QString &msg);void sigReceivePix(QByteArray pix);void sigReceiveFile(QByteArray data,QString fname);
};#endif // COMMONINTERFACE_H

commoninterface.cpp

#include "commoninterface.h"CommonInterface::CommonInterface(QObject *parent) : CommonInterfaceSource(parent)
{}void CommonInterface::onMessage(QString msg)
{emit sigReceiveMsg(msg);
}void CommonInterface::onPixmap(QByteArray pix)
{emit sigReceivePix(pix);
}void CommonInterface::onFile(QByteArray data,QString fname)
{emit sigReceiveFile(data,fname);
}void CommonInterface::sendMsg(const QString &msg)
{emit sigMessage(msg);
}void CommonInterface::sendPixmap(QByteArray pix)
{emit sigPixmap(pix);
}void CommonInterface::sendFile(QByteArray data,QString fname)
{emit sigFile(data,fname);
}

2.4主界面

主界面创建了三个按钮,分别用于发送文字、图片、文件。一个LineEdit(发送文字)、一个TextEdit(接收文字)、一个Label(接收图片)。

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include "commoninterface.h"
#include <QRemoteObjectHost>
#include <QPixmap>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();
private slots:void on_pushButton_clicked();void onReceiveMsg(const QString &msg);void on_pushButton_2_clicked();void onReceivePix(QByteArray pix);void on_pushButton_3_clicked();void onReceiveFile(QByteArray data,QString fname);private:Ui::Widget *ui;CommonInterface *m_pInterface = nullptr;QRemoteObjectHost *m_pHost = nullptr;void init();
};
#endif // WIDGET_H

widget.cpp:

#include "widget.h"
#include "ui_widget.h"
#include <QFileDialog>
#include <QBuffer>
#include <QDebug>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);setWindowTitle("server");init();
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{QString msg = ui->lineEdit->text();if(!msg.isEmpty()){m_pInterface->sendMsg(msg);}ui->textEdit->append(QString("Server:")+msg);ui->lineEdit->clear();
}void Widget::onReceiveMsg(const QString &msg)
{ui->textEdit->append(QString("Client:")+msg);
}void Widget::init()
{m_pHost = new QRemoteObjectHost(this);//m_pHost->setHostUrl(QUrl("tcp://192.168.137.100:8081"));m_pHost->setHostUrl(QUrl("local:interfaces"));m_pInterface = new CommonInterface(this);m_pHost->enableRemoting(m_pInterface);connect(m_pInterface,&CommonInterface::sigReceiveMsg,this,&Widget::onReceiveMsg);connect(m_pInterface,&CommonInterface::sigReceivePix,this,&Widget::onReceivePix);connect(m_pInterface,&CommonInterface::sigReceiveFile,this,&Widget::onReceiveFile);
}void Widget::on_pushButton_2_clicked()
{QString file = QFileDialog::getOpenFileName(this,"open","./","*.png *.jpg");if(file.isEmpty())return;QPixmap pix;pix.load(file,"png");if(pix.isNull())qDebug()<<"error";QByteArray ba;QBuffer bf(&ba);pix.save(&bf,"png");m_pInterface->sendPixmap(ba);
}void Widget::onReceivePix(QByteArray pix)
{ui->textEdit->append("收到图片");qDebug()<<pix.size();QPixmap p;p.loadFromData(pix);ui->label->setPixmap(p);
}void Widget::on_pushButton_3_clicked()
{QString file = QFileDialog::getOpenFileName(this,"open","./","*.*");if(file.isEmpty())return;QFile f(file);if(f.open(QIODevice::ReadOnly)){QByteArray ba = f.readAll();QFileInfo info(file);file = info.fileName();m_pInterface->sendFile(ba,file);f.close();}
}void Widget::onReceiveFile(QByteArray data,QString fname)
{ui->textEdit->append("收到文件:"+fname);QFile file(fname);if(file.open(QIODevice::WriteOnly)){file.write(data);file.close();}
}

到此,服务端完成。

三、使用QtRO编写客户端

2.1rep文件是通用的,不用重复创建,这里直接添加到工程。

pro:

QT += remoteobjects
REPC_REPLICA += \interface.rep

注意!!!这里关键字变成了REPC_REPLICA和服务端的不一样!!所以到下一步以后生产的头文件名称也不一样!

2.2构建项目,在输出目录找到rep_interface_replica.h文件,放进工程。

2.3客户端中不需要再去创建CommonInterface类了,我们直接在主界面widget.h中编写。客户端和服务端的ui界面一样。

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QRemoteObjectNode>
#include "rep_interface_replica.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();void onReceiveMsg(QString msg);void on_pushButton_2_clicked();void onReceivePix(QByteArray pix);void on_pushButton_3_clicked();void onReceiveFile(QByteArray ba,QString fname);private:Ui::Widget *ui;QRemoteObjectNode *m_pRemoteNode = nullptr;InterfaceReplica *m_pInterface = nullptr;void init();
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QBuffer>
#include <QFileDialog>
#include <QDebug>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);setWindowTitle("Client");init();
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{QString msg = ui->lineEdit->text();if(!msg.isEmpty()){m_pInterface->onMessage(msg);}ui->textEdit->append("Client:"+msg);ui->lineEdit->clear();
}void Widget::onReceiveMsg(QString msg)
{ui->textEdit->append("Server:"+msg);
}void Widget::init()
{m_pRemoteNode = new QRemoteObjectNode(this);m_pRemoteNode->connectToNode(QUrl("local:interfaces"));m_pInterface = m_pRemoteNode->acquire<CommonInterfaceReplica>();connect(m_pInterface,&CommonInterfaceReplica::sigMessage,this,&Widget::onReceiveMsg);connect(m_pInterface,&CommonInterfaceReplica::sigPixmap,this,&Widget::onReceivePix);connect(m_pInterface,&CommonInterfaceReplica::sigFile,this,&Widget::onReceiveFile);
}void Widget::on_pushButton_2_clicked()
{QString file = QFileDialog::getOpenFileName(this,"open","./","*.png *.jpg");if(file.isEmpty())return;QPixmap pix;pix.load(file,"png");if(pix.isNull())qDebug()<<"error";QByteArray ba;QBuffer bf(&ba);pix.save(&bf,"png");m_pInterface->onPixmap(ba);
}void Widget::onReceivePix(QByteArray pix)
{ui->textEdit->append("收到图片");qDebug()<<pix.size();QPixmap p;p.loadFromData(pix);ui->label->setPixmap(p);
}void Widget::on_pushButton_3_clicked()
{QString file = QFileDialog::getOpenFileName(this,"open","./","*.*");if(file.isEmpty())return;QFile f(file);if(f.open(QIODevice::ReadOnly)){QByteArray ba = f.readAll();QFileInfo info(file);file = info.fileName();m_pInterface->onFile(ba,file);f.close();}
}void Widget::onReceiveFile(QByteArray data,QString fname)
{ui->textEdit->append("收到文件:"+fname);QFile file(fname);if(file.open(QIODevice::WriteOnly)){file.write(data);file.close();}
}

到此,客户端和服务端都完成了,他们之间可以互相收发文字、图片、文件。

四、QtRO支持的参数类型

4.1 从2.1中我们可以知道,QtRO可以收发的数据类型由rep文件中定义的信号和槽决定的,那是不是可以定义任何数据类型,实现任何数据类型的收发呢?显然不是的,QRO允许发送的信号参数类型包括以下几种:

1.基本数据类型:如int、bool、char、float、double等。
2.Qt的核心类:如QString、QList、QMap等。
3.Qt的自定义类:只要这些类实现了序列化功能,就可以作为信号参数。

因此我的图片收发用的是QByteArray,而不是直接用QPixmap。

上述代码中连接方式是本机内通信,若要拓展为远端通信,可以把URL设置为如下格式:

m_pHost->setHostUrl(QUrl("tcp://192.168.137.100:8081"));

五、适合使用QtRO的场合

只有在服务端和客户端均用Qt开发的时候,适合使用QtRO方式。使用QtRO使得接口定义和实现更加方便。当已经有服务端程序,仅用Qt编写客户端时,就无法使用QtRO了。

相关文章:

QtRO(Qt Remote Objects)分布式对象远程通信

一、什么是QtRO Qt Remote Objects&#xff08;QRO&#xff09;是Qt提供的一种用于实现远程对象通信的机制。 QtRO支持两种类型的通信&#xff1a;RPC&#xff08;远程过程调用&#xff09;和LPC&#xff08;本地进程通信&#xff09;。 RPC&#xff08;远程过程调用&#xf…...

【K8s】1# 使用kuboard-spray安装K8s集群

文章目录 搭建k8s集群1.推荐配置1.1.服务器配置1.2.软件版本 2.使用Kuboard-Spray安装k8s集群2.1.配置要求2.2.操作系统兼容性2.3.安装 Kuboard-Spray2.4.加载离线资源包2.5.规划并安装集群2.6.安装成功2.7.访问集群 3.涉及的命令3.1.linux 4.问题汇总Q1&#xff1a;启动离线集…...

leetCode算法—12. 整数转罗马数字

12. 整数转罗马数字 难度&#xff1a;中等 ** 罗马数字包含以下七种字符&#xff1a; I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如&#xff0c; 罗马数字 2 写做 II &#xff0c;即…...

使用OpenCV4实现工业缺陷检测的六种方法

目录 1 机器视觉2 缺陷检测3 工业上常见缺陷检测方法 1 机器视觉 机器视觉是使用各种工业相机&#xff0c;结合传感器跟电气信号实现替代传统人工&#xff0c;完成对象识别、计数、测量、缺陷检测、引导定位与抓取等任务。其中工业品的缺陷检测极大的依赖人工完成&#xff0c;…...

Excel 获取当前行的行数

ROW() 获取当前行 ROW()1 获取当前行然后支持二次开发...

R语言【stringr】——str_detect 检测是否存在字符串的匹配项

Package stringr version 1.5.1 str_detect(string, pattern, negate FALSE) 参数【string】&#xff1a;输入向量。既可以是字符向量&#xff0c;也可以是强制作为一个字符向量。 参数【pattern】&#xff1a;要寻找的模式。默认解释为正则表达式&#xff0c;如 vignette(&…...

【SpringMVC】SpringMVC的请求与响应

文章目录 0. Tomcat环境的配置1. PostMan工具介绍创建WorkSpace建立新的请求 2. 请求映射路径案例结构与代码案例结构案例代码 案例存在问题解决方案方法方法升级版——配置请求路径前缀注解总结 3. Get请求与Post请求案例结构与案例代码案例结构案例代码 Get请求Post请求接收中…...

Spring Boot3通过GraalVM生成exe执行文件

一、安装GraalVM 1、官网&#xff1a;https://www.graalvm.org/downloads/ 2、配置环境变量 2.1、环境变量必须使用JAVA_HOME&#xff0c;否则会出现问题 2.2、在系统变量配置Path,%JAVA_HOME%\bin&#xff0c;注意必须放在顶部第一位 2.3、配置jdk的环境变量&#xff0c;在P…...

【Amazon 实验②】使用缓存策略及源请求策略,用于控制边缘缓存的行为及回源行为

文章目录 1. 了解缓存策略和源请求策略1.1 使用缓存键和缓存策略 实验&#xff1a;使用CloudFront缓存策略和缓存键控制缓存行为 接上一篇文章【Amazon 实验①】使用 Amazon CloudFront加速Web内容分发&#xff0c;我们现在了解和配置如何使用缓存策略及源请求策略&#xff0c;…...

达梦数据对比工具的部署与使用

1、拷贝达梦软件bin目录到Oracle服务器&#xff08;root用户&#xff09; 压缩Linux rh6 x86版本的达梦数据库bin目录&#xff0c;例如压缩文件为dmbin.tar.gz&#xff0c;将文件拷贝到Oracle服务器指定目录并解压&#xff08;如&#xff1a;/home/oracle/dmbin&#xff09;&a…...

TLC2543(12位A/D转换器)实现将输入的模拟电压显示到数码管上

代码&#xff1a; #include <reg51.h> #define uchar unsigned char #define uint unsigned int// 数码管0-9 unsigned char seg[] {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; sbit SDO P1^0; sbit SDI P1^1; sbit CS P1^2; sbit CLK P1^3; s…...

npm的使用技巧

以下是一些NPM&#xff08;Node Package Manager&#xff09;的使用技巧&#xff1a; 1. **获取帮助**&#xff1a; - 使用 npm help 或者 npm <command> --help 可以获取关于特定命令的帮助信息。 2. **命令自动完成**&#xff1a; - 在 Bash、Zsh 等 shell 中&…...

MySQL 5.6的新特性

MySQL 5.6是一个主要的版本发布&#xff0c;它在性能、可伸缩性、可靠性和可用性方面引入了多项重要改进和新特性。它在2013年发布&#xff0c;相比于它的前身MySQL 5.5&#xff0c;MySQL 5.6带来了以下关键升级&#xff1a; 优化的InnoDB存储引擎&#xff1a;MySQL 5.6中的Inn…...

大模型重构云计算:AI原生或将改变格局

摘要&#xff1a;随着AI技术的快速发展&#xff0c;大模型正逐渐改变云计算的格局。本文将深入探讨大模型如何重构云计算&#xff0c;并分析其对云计算的影响。 一、开篇引言 近年来&#xff0c;人工智能技术的飞速发展&#xff0c;特别是大模型的崛起&#xff0c;正在对云计算…...

一文讲清什么是TypeScript装饰器以及如何使用TypeScript装饰器

TypeScript 装饰器是什么&#xff1f; 装饰器&#xff08;Decorator&#xff09;是TypeScript提供的一个高级语法&#xff0c;它类似于一种特殊类型的声明&#xff0c;可以附加到类声明&#xff0c;方法&#xff0c;访问符&#xff0c;属性或参数上。装饰器主要以函数的形式出…...

恶意软件样本行为分析——Process Monitor和Wireshark

1.1 实验名称 恶意软件样本行为分析 1.2 实验目的 1) 熟悉 Process Monitor 的使用 2) 熟悉抓包工具 Wireshark 的使用 3) VMware 的熟悉和使用 4) 灰鸽子木马的行为分析 1.3 实验步骤及内容 第一阶段&#xff1a;熟悉 Process Monitor 的使用 利用 Process …...

【XR806开发板试用】通过http请求从心知天气网获取天气预报信息

1. 开发环境搭建 本次评测开发环境搭建在windows11的WSL2的Ubuntu20.04中&#xff0c;关于windows安装WSL2可以参考文章: Windows下安装Linux(Ubuntu20.04)子系统&#xff08;WSL&#xff09; (1) 在WSL的Ubuntu20.04下安装必要的工具的. 安装git: sudo apt-get install git …...

NPM介绍与使用

什么是NPM&#xff1f; NPM&#xff08;Node Package Manager&#xff09;是一个强大的包管理工具&#xff0c;专门用于Node.js应用程序的依赖管理。它允许开发者轻松地分享、安装、更新和管理项目中使用的库、工具和框架。 NPM的安装 在使用NPM之前&#xff0c;请确保你的机…...

servlet +thymeleaf渲染引擎

servlet thymeleaf渲染引擎 一、maven坐标 <dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf</artifactId><version>3.0.12.RELEASE</version> <!-- 使用适当的Thymeleaf版本 --> </dependency> &…...

10分钟了解nextTick,并实现简易版本的nextTick

在 Vue.js 中&#xff0c;有一个特殊的方法 nextTick&#xff0c;它在 DOM 更新后执行一段代码&#xff0c;起到等待 DOM 绘制完成的作用。本文会详细介绍 nextTick 的原理和使用方法&#xff0c;并实现一个简易版的 nextTick&#xff0c;加深对它的理解。 一. 什么是 nextTic…...

告别手动标注!用RexUniNLU零样本模型自动提取电商评论情感

告别手动标注&#xff01;用RexUniNLU零样本模型自动提取电商评论情感 1. 电商评论分析的痛点与解决方案 电商平台每天产生海量用户评论&#xff0c;这些评论蕴含着宝贵的用户反馈和市场洞察。传统的情感分析方法通常面临两大难题&#xff1a; 标注成本高&#xff1a;需要大…...

数字化、智能化、移动化,人力资源系统革新的三大法宝!

人力资源系统革新&#xff0c;打造企业人才发展新引擎在当今竞争激烈的商业环境中&#xff0c;企业的人才发展成为了决定其成败的关键因素之一。然而&#xff0c;传统的人力资源管理系统往往存在着诸多问题&#xff0c;如流程繁琐、数据不精准、缺乏智能化等&#xff0c;这些问…...

【搭建单双目散斑结构光Demo】

介绍 最近搭了一个用于研究的单目散斑结构光的硬件Demo。发射端使用VCSEL模组投影散斑&#xff0c;接收端使用工业相机采集图像。工业相机曝光时输出同步信号给驱动板&#xff0c;驱动板控制VCSEL发光投射出散斑图案&#xff0c;同步时间精度可以达到十微秒。也可以配两个工业…...

OpenClaw成本优化方案:自建Qwen3-VL:30B替代高价多模态API

OpenClaw成本优化方案&#xff1a;自建Qwen3-VL:30B替代高价多模态API 1. 为什么需要关注OpenClaw的成本问题 第一次用OpenClaw完成多模态任务时&#xff0c;我被账单吓了一跳。当时需要处理200张产品图片的分类和描述生成&#xff0c;调用某商业多模态API后&#xff0c;费用…...

嵌入式正交编码器软件解码库设计与实现

1. QuadratureEncoder 库概述QuadratureEncoder 是一个专为嵌入式系统设计的正交编码器信号处理库&#xff0c;面向 STM32、ESP32、nRF52 等主流 MCU 平台&#xff0c;提供高精度、低开销、抗干扰的旋转位置与速度检测能力。该库不依赖特定硬件外设&#xff08;如 STM32 的 TIM…...

不用命令行!Win11任务栏图标消失的图形化解决方案(Explorer重启神器推荐)

Win11任务栏图标消失&#xff1f;5种可视化修复方案与深度解析 每次切换虚拟桌面后&#xff0c;Win11任务栏图标集体"失踪"的毛病&#xff0c;堪称微软系统最顽固的"幽灵故障"之一。作为从Windows 95时代就存在的资源管理器痼疾&#xff0c;这个问题在Win1…...

基于YOLOv11姿态检测的AI健身助手具备实时姿态识别、运动计数与反馈、训练记录和计划制定功能

基于YOLOv11姿态检测的AI健身助手 ✨ 功能特点 实时运动计数 - 自动计算您的健身次数多种运动支持 - 包括深蹲、俯卧撑、仰卧起坐、哑铃运动等十多种先进的姿态检测 - 采用YOLOv11实现精准跟踪模型切换功能 - 可以在小型(更快)和大型(更精确)YOLOv11模型之间轻松切换可视化反馈…...

阿联酋人工智能大学:AI能在战争迷雾中做出理性判断吗?

这项由阿联酋穆罕默德本扎耶德人工智能大学和美国马里兰大学共同完成的研究发表于2026年3月&#xff0c;论文编号为arXiv:2603.16642v1。有兴趣深入了解的读者可以通过该编号查询完整论文。在人类历史上&#xff0c;预测战争走向一直是个极其困难的任务。就像我们很难在暴风雨中…...

浒浦潮汐表查询2026-03-28

位置&#xff1a;浒浦&#xff0c;日期&#xff1a;2026-03-28&#xff0c;农历&#xff1a;丙午[马]年二月初十&#xff0c;星期&#xff1a;星期六&#xff0c;潮汐类型&#xff1a;小潮死汛最高水位&#xff1a;275.00cm&#xff0c;最低水位&#xff1a;122.00cm&#xff0…...

AI药物研发加速发现:DeepChem深度学习框架实战指南

AI药物研发加速发现&#xff1a;DeepChem深度学习框架实战指南 【免费下载链接】deepchem Democratizing Deep-Learning for Drug Discovery, Quantum Chemistry, Materials Science and Biology 项目地址: https://gitcode.com/GitHub_Trending/de/deepchem 深度学习药…...