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

简介

Qt Remote Object简称QtRO,这是Qt5.9以后官方推出来的新模块,专门用于进程间通信(IPC)。是基于Socket来封装的,兼容LPC和RPC。LPC即Local Process Communication,而RPC是指Remote Process Communication,两者都属于IPC。如果用于LPC,则QtRO使用QLocalSocket;如果是用于RPC,则使用QTcpSocket。

它最大的特点是使得远端通信能与本机通信一样使用信号槽的方式来收发信息。

每个进程通过QRemoteObjectNode接入QtRO网络。功能提供节点(可以理解为服务器)需要使用QRemoteObjectHost将一个提供实际功能的QObject派生类注册进QtRO网络中,然后其他使用该功能的程序则通过各自的QRemoteObjectNode连接到该Host上,然后acquire一个该功能对象的Replica。等到该Replica初始化好后,该程序就能够使用Replica中的信号、槽以及属性,就好像功能类就在本地一样。

优点:
  1. 使用 QtRO 则天生支持Qt 自带的类型,如 QString 、QByteArray 。
  2. 而且定义的接口支持信号槽。
缺点:

host 不能直接访问当前连接的 node,服务端是所有已连接的 node 共享的,如果 host-source 发信号,那么所有连接的 node 都会收到这个信号。从这点来看 QtRO 更适合单个客户端的进程交互,不适合多个客户端的并发访问,多个客户端时要独立操作则不该使用信号,可以通过槽函数返回值来返回结果。

关键步骤

要使用QtRO有几个关键步骤,我们暂且将两个端分为Server和Client。

Server端需要把功能类通过QRemoteObjectHost的enableRemoting方法共享出来

Client连接到该QRemoteObjectHost,然后acquire到Replica

QtRO会自动初始化该Replica,待初始化完后客户端就可以用该Replica。

QtRO支持的参数类型

QtRO可以收发的数据类型由rep文件中定义的信号和槽决定的,QRO允许发送的信号参数类型包括以下几种:

1.基本数据类型:如int、bool、char、float、double等。

2.Qt的核心类:如QString、QList、QMap等。

3.Qt的自定义类:只要这些类实现了序列化功能,就可以作为信号参数。

使用QtRO编写服务端
创建rep文件

rep文件是一种DSL(Domain Specific Language),专门用于定义QtRO接口。在编译的时候,该文件会首先经过repc.exe这个程序处理,生成对应的头文件和源文件。只要安装Qt时选择了Qt RemoteObjects模块,repc.exe就在Qt安装目录的bin目录中。

如 rep文件

#include <QObject>#include <QString>POD VarInfo(QString varName,QString value,);ENUM PlatType{P_Unknown = -1,       //未知平台P_Firm = 0,P_Fit = 1,P_Speed = 2};class CommonInterface{SIGNAL(sigMessage(VarInfo msg));   //server下发消息给clientSLOT(bool onMessage(QString msg,PlatTypeEnum::PlatType type)); //server接收client的消息PROP(QString strname);         // Property}

Rep 文件的介绍见:Qt Remote Objects Compiler | Qt Remote Objects 5.15.16

PROP

Q_PROPERTY元素是通过在rep文件中使用PROP关键字创建的。语法是PROP关键字后跟括号中的定义,其中定义是类型、名称和(可选的)默认值或属性。

 PROP(QString strname);  

CLASS

CLASS关键字为从QObject派生的对象生成特殊的Q_PROPERTY元素。这些属性与SOURCEONLYSETTER具有相同的语义。语法是CLASS关键字后跟属性名,然后是括在括号中的子对象类型。

Signal

Signal方法是通过使用rep文件中的SIGNAL关键字创建的。 用法是声明SIGNAL,后跟用括号括起来的所需签名。应该跳过void返回值。

SIGNAL(sigMessage(VarInfo msg));   

SLOT

插槽方法是使用rep文件中的Slot关键字创建的。 用法是声明SLOT,后跟用括号括起来的所需签名。返回值可以包含在声明中。如果返回值被跳过,将在生成的文件中使用void。

SLOT(bool onMessage(QString msg,PlatTypeEnum::PlatType type));

ENUM

枚举(在QtRO中使用C++ enum和Qt的Q_enum的组合)是使用ENUM关键字描述的。

ENUM PlatType{

    P_Unknown = -1,       //未知平台

    P_Firm = 0,

    P_Fit = 1,

    P_Speed = 2

};

POD

Plain Old Data 普通旧数据(POD)是一个描述简单数据集合的术语,类似于C++结构.即自定义结果类型。

POD VarInfo(

   QString varName,

   QString value,

   );

REPC_SOURCE

指定项目中用于生成源文件的所有表示文件的名称。即用在服务端

REPC_SOURCE += \

../Reps/commoninterface.rep

REPC_REPLICA

指定项目中用于生成副本头文件的所有rep文件的名称,即用在客户端。

REPC_REPLICA += \

        ../Reps/commoninterface.rep

配置rep文件

在server端的pro文件中将rep文件添加进来

REPC_SOURCE += \

../Reps/commoninterface.rep

接着添加QtRO模块

QT  += remoteobjects

直接qmake,编译,这时候repc.exe会将rep文件生成对应的头文件,在程序输出目录下可以找到.

打开文件如下图:

继承实现功能

继承自动生成的这个CommonInterfaceSimpleSource类,并且实现其中的所有纯虚函数。如果没有 加上PROP(QString strname);  就不会生成CommonInterfaceSimpleSource类,直接继承CommonInterfaceSource类。

头文件

#ifndef COMMONINTERFACE_H#define COMMONINTERFACE_H#include "rep_commoninterface_source.h"   //在这里引用的是debug目录下编译的rep_commoninterface_source.hclass CommonInterface : public CommonInterfaceSimpleSource{Q_OBJECTpublic:explicit CommonInterface(QObject * parent = nullptr);//这个就是rep文件设置,接收数据的虚函数virtual bool onMessage(QString msg, PlatTypeEnum::PlatType type);void senddata(QString msg);signals:void sigReceiveMsg(QString msg);//把从客户端接收到的数据发送到界面上};#endif // COMMONINTERFACE_H

源文件

#include "CommonInterface.h"CommonInterface::CommonInterface(QObject *parent){}bool CommonInterface::onMessage(QString msg, PlatTypeEnum::PlatType type){if(type == PlatTypeEnum::PlatType::P_Firm){emit sigReceiveMsg(msg);}return true;}void CommonInterface::senddata(QString msg){VarInfo info;info.setValue(msg);info.setVarName("1");emit sigMessage(info);}
初始化QtRO并调用

头文件

#ifndef DIALOG_H#define DIALOG_H#include <QDialog>#include "CommonInterface.h"QT_BEGIN_NAMESPACEnamespace Ui { class Dialog; }QT_END_NAMESPACEclass Dialog : public QDialog{Q_OBJECTpublic:Dialog(QWidget *parent = nullptr);~Dialog();void init();private slots:void onReceiveMsg(QString msg);void on_pushButton_clicked();private:Ui::Dialog *ui;CommonInterface * m_pInterface ;QRemoteObjectHost * m_pHost ;};#endif // DIALOG_H

源文件

#include "dialog.h"#include "ui_dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent), ui(new Ui::Dialog){init();ui->setupUi(this);setWindowTitle("Server");}Dialog::~Dialog(){delete ui;}void Dialog::init(){m_pHost = new QRemoteObjectHost(this);m_pHost->setHostUrl(QUrl("local:interfaces"));m_pInterface = new CommonInterface(this);m_pHost->enableRemoting(m_pInterface);connect(m_pInterface,&CommonInterface::sigReceiveMsg,this,&Dialog::onReceiveMsg);}void Dialog::onReceiveMsg(QString msg){ui->textEdit->clear();ui->textEdit->setText(msg);}void Dialog::on_pushButton_clicked(){QString text = ui->lineEdit->text();m_pInterface->senddata(text);}

这里是本机中不同进程的通信,可以HostURL中字符串格式为"local:xxxx",其中xxxx必须是唯一的字符串,不同和其他程序有冲突,否则将会无法连接。

使用QtRO编写客户端
配置rep文件

Client端和Server必须共用同一个rep文件,在工程文件pro中添加

REPC_REPLICA += \

    ../Reps/commoninterface.rep

添加QtRO模块

QT       += remoteobjects

client添加完rep过后,直接编译,然后会在输出目录生成一个文件

打开文件:

初始化QtRO并调用

和server端不同的是,client端不需要重新实现功能类。直接初始化并调用即可。

头文件

#ifndef DIALOG_H#define DIALOG_H#include <QDialog>#include "rep_CommonInterface_replica.h"QT_BEGIN_NAMESPACEnamespace Ui { class Dialog; }QT_END_NAMESPACEclass Dialog : public QDialog{Q_OBJECTpublic:Dialog(QWidget *parent = nullptr);~Dialog();private:void init();private slots:void on_pushButton_clicked();void onReceiveMsg(VarInfo msg);private:Ui::Dialog *ui;QRemoteObjectNode * m_pRemoteNode ;CommonInterfaceReplica * m_pInterface ;};#endif // DIALOG_H

源文件

#include "dialog.h"#include "ui_dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent), ui(new Ui::Dialog){init();ui->setupUi(this);setWindowTitle("Client");}Dialog::~Dialog(){delete ui;}void Dialog::init(){m_pRemoteNode = new QRemoteObjectNode(this);m_pRemoteNode->connectToNode(QUrl("local:interfaces"));m_pInterface = m_pRemoteNode->acquire<CommonInterfaceReplica>();connect(m_pInterface,&CommonInterfaceReplica::sigMessage,this,&Dialog::onReceiveMsg);}void Dialog::on_pushButton_clicked(){QString msg = ui->lineEdit->text();QRemoteObjectPendingReply<bool>  ret =  m_pInterface->onMessage(msg,PlatTypeEnum::PlatType::P_Firm); //异步调用槽发送消息给服务器bool bret = ret.waitForFinished();//等待函数if(bret){bool bval = ret.returnValue();ui->lineEdit->clear();}else{QString err = "超时";}}void Dialog::onReceiveMsg(VarInfo msg){ui->textEdit->clear();ui->textEdit->setText(msg.varName() + ":" + msg.value());}

注意:在客户端调用服务端的槽函数(也是虚函数,通过rep文件设置),属于异步调用。如果该槽函数有返回值的,一般要通过等待函数waitForFinished,并通过QRemoteObjectPendingReply类的returnValue获取返回值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/768102.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Camera入门基础知识

一、camera介绍 1.1 camera硬件组成 camera一般由Lens、VCM音圈马达、底座支架、Sensor、Driver IC、output interface组成。如下图: 这里面要注意的是有些摄像头模组有VCM,有些则没有,有些output interface输出的是CSI信号,有的输出的是串行信号,需要接解串器。…

全新的分布式锁,功能简单且强大

分布式锁是分布式系统中一个极为重要的工具。 目前有多种分布式锁的设计方案&#xff0c;比如借助 redis&#xff0c;mq&#xff0c;数据库&#xff0c;zookeeper 等第三方服务系统来设计分布式锁。 tldb 提供的分布式锁&#xff0c;主要是要简化这个设计的过程&#xff0c;提…

面向对象-继承-使用细节

面向对象-继承-使用细节 1、子类继承了父类所有的属性和方法&#xff0c;非私有的属性和方法可以在子类中直接访问&#xff0c;但是私有的属性和方法不能在子类中直接访问&#xff0c;要通过父类提供公共的方法去访问。 2、子类必须调用父类的构造器&#xff0c;完成对父类的初…

PCB布线中晶振电容、电源大小电容、电源电容的设计细节

嵌入式软硬件爱好者 一张手册走天下。嵌入式单片机/Linux/Openwrt/电子电路技术交流分享。//主打一个技术层面的剑走偏锋&#xff0c;直击众人重视和不重视的重点//专注基础&#xff0c;才能走的更远 晶振电容 晶振旁边的电容在电路设计中不是用于滤波的。实际上&#xff0c;…

RIP,EIGRP,OSPF的区别

1.路由协议 能否选择出最优路径 2.路由协议 是否能够完成故障切换/多久能够完成故障切换 3.路由协议 是否会占用过大硬件资源 -- RIP -- 路由信息协议 跳数:一次三层设备的转发算一跳 中间隔的设备数量 不按照链路带宽来算 Rip认为路径一样,这个时候。 下面这个跳数不…

每日一题 --- 反转链表[力扣][Go]

反转链表 题目&#xff1a;206. 反转链表 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&a…

阿里云服务器价格购买价格表,2024新版报价查询

2024年腾讯云服务器优惠价格表&#xff0c;一张表整理阿里云服务器最新报价&#xff0c;阿里云服务器网整理云服务器ECS和轻量应用服务器详细CPU内存、公网带宽和系统盘详细配置报价单&#xff0c;大家也可以直接移步到阿里云CLUB中心查看 aliyun.club 当前最新的云服务器优惠券…

(Linux 学习十二)文件查找和文件压缩

一.文件查找 which 命令查找 也可以用 whereis find 文件查找&#xff0c;针对文件名 locate 文件查找&#xff0c;依赖数据库alias 别名 alias yyy ls --colorauto -l yyy //相当于别名 查看文件which ls //查找ls 命令位置 whereis vim //也是查找命令locate …

Jackson 2.x 系列【2】生成器 JsonGenerator

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Jackson 版本 2.17.0 源码地址&#xff1a;https://gitee.com/pearl-organization/study-seata-demo 文章目录 1. 前言2. 案例演示2.1 创建 JsonFactory2.2 创建 JsonGenerator2.3 写入操作2.4 查…

pta-洛希极限

科幻电影《流浪地球》中一个重要的情节是地球距离木星太近时&#xff0c;大气开始被木星吸走&#xff0c;而随着不断接近地木“刚体洛希极限”&#xff0c;地球面临被彻底撕碎的危险。但实际上&#xff0c;这个计算是错误的。 洛希极限&#xff08;Roche limit&#xff09;是一…

javase day11笔记

第十一天课堂笔记 构造代码块 { } 给 所有对象 共性特点 进行初始化操作 创建对象时在堆区对象中存放实例变量,同时执行构造代码块 执行顺序:静态代码块—>非静态代码块—>构造方法 继承★★★ 将多个类中相同的实例变量和实例方法 , 单独存放到一个类中,成为父类…

基于Java中的SSM框架实现快餐店线上点餐系统项目【项目源码+论文说明】计算机毕业设计

基于Java中的SSM框架实现快餐店线上点餐系统演示 摘要 随着计算机互联网的高速发展。餐饮业的发展也加入了电子商务团队。各种网上点餐系统纷纷涌现&#xff0c;不仅增加了商户的销售量和营业额&#xff0c;而且为买家提供了极大的方便&#xff0c;足不出户&#xff0c;就能订…

云计算安全分析

目录 一、概述 二、《云计算服务安全指南》的云安全风险分析 2.1 客户对数据和业务系统的控制能力减弱 2.2 客户与云服务商之间的责任难以界定 2.3 可能产生司法管辖权问题 2.4 数据所有权保障面临风险 2.5 数据保护更加困难 2.6 数据残留 2.7 容易产生对云服务商的过度…

[AIGC] SQL中的数据添加和操作:数据类型介绍

SQL&#xff08;结构化查询语言&#xff09;作为一种强大的数据库查询和操作工具&#xff0c;它能够完成从简单查询到复杂数据操作的各种任务。在这篇文章中&#xff0c;我们主要讨论如何在SQL中添加&#xff08;插入&#xff09;数据&#xff0c;以及在数据操作过程中&#xf…

2021年XX省赛职业院校技能大赛”高职组 计算机网络应用赛项 网络构建模块竞赛真题

“2021年XX省赛职业院校技能大赛”高职组 计算机网络应用赛项 网络构建模块竞赛真题 目录 一&#xff0e;考试说明 1 二&#xff0e;模块B网络构建 2 &#xff08;一&#xff09;任务描述 2 &#xff08;二&#xff09;任务清单 9 一&#xff0e;考试说明 本模块比赛时间为…

使用pandas进行数据清洗

采集到原始的数据中会存在一些噪点数据&#xff0c;噪点数据是对分析无意义或者对分析起到偏执作用的数据。如何清洗&#xff1a; 清洗空值/缺失值清洗重复值清洗异常值 import pandas as pd from pandas import DataFrame,Series import numpy as np pandas处理空值操作 i…

C语言中如何动态分配内存并进行操作

C语言文章更新目录 C语言学习资源汇总&#xff0c;史上最全面总结&#xff0c;没有之一 C/C学习资源&#xff08;百度云盘链接&#xff09; 计算机二级资料&#xff08;过级专用&#xff09; C语言学习路线&#xff08;从入门到实战&#xff09; 编写C语言程序的7个步骤和编程…

32 mars3d 官方 demo 可以跑起来, 但是自己拷贝的 demo 跑不起来

前言 这个问题是 同事碰到的一个问题 主要的影响因素在于 官方的 demo 从 mars3d-cesium 中暴露了一部分文件作为 http 服务, 然后 我们自己的 case 里面没有这部分服务, 然后 导致 js 访问不到 以及 大部分的 css, js, img 等等 静态资源 访问不到 Cesium is not define…

11.创建后台系统项目

后台系统项目 兼容性 vite官网&#xff1a;https://vitejs.dev/ vite中文网&#xff1a;https://cn.vitejs.dev/ vite需要node.js版本 >14.0.0&#xff0c;建议16 node -v 查看版本号 创建项目 进入存放目录 执行命令 npm create vitelatest 选择vue框架 选择typescript…

苍穹外卖笔记

苍穹外卖 DAY01nginx反向代理MD5加密yapi进行接口导入Swagger介绍 DAY02新增员工需求分析和设计写相关代码测试(1. 后端文档测试 2. 前后端联调代码完善 员工分页查询DAY01 02涉及到的知识 DAY01 nginx反向代理 MD5加密 拓展&#xff1a;spring security jwt 提供了更强大灵…