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下发消息给client

    SLOT(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.h



class CommonInterface : public CommonInterfaceSimpleSource

{

    Q_OBJECT

public:

    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_NAMESPACE

namespace Ui { class Dialog; }

QT_END_NAMESPACE



class Dialog : public QDialog

{

    Q_OBJECT



public:

    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_NAMESPACE

namespace Ui { class Dialog; }

QT_END_NAMESPACE



class Dialog : public QDialog

{

    Q_OBJECT

public:

    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获取返回值。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

瑞士百达资产管理有限公司拟增三大去中心化数字加密货币支付接口!

简介: 瑞士百达集团成立于1805年,欧洲第三大财富管理公司, 集团拥有约 5,300 名员工,其中包括 900 名投资经理。它在金融服务中心拥有 30 个办事处网络,包括在日内瓦、卢森堡、拿骚、香港和新加坡的注册银行,百达集团管理的资产总额达6380亿瑞士法郎(7670亿美元)。 瑞士百达资…

触手可及的社交:揭示Facebook如何让每个人都能参与其中

引言 在当今社会&#xff0c;Facebook已经成为了人们日常生活中不可或缺的一部分。无论是与朋友、家人保持联系&#xff0c;还是参与社群讨论、获取新闻信息&#xff0c;Facebook都提供了一个触手可及的社交平台。本文将探讨Facebook如何让每个人都能轻松参与其中&#xff0c;…

ClickHouse01-什么是ClickHouse

什么是ClickHouse&#xff1f; 关于发展历史存在的优势与劣势什么是它风靡的原因&#xff1f; 什么是ClickHouse&#xff1f; 官方给出的回答是&#xff0c;它是一个高性能、列式存储、基于SQL、供在线分析处理的数据库管理系统 当然这边不得不提到OLAP(Online Analytical Pr…

代码随想录day24(1)二叉树:最大二叉树(leetcode654)

题目要求&#xff1a; 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下&#xff1a; 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出的最大二叉树。右子树是通过数组中最大值右边部分构造出的最大二叉树。 通过给定的数组构…

【C++】AVL树的两单旋和两双旋

目录 1. 新节点插入较高左子树的左侧---左左&#xff1a;右单旋 代码 2. 新节点插入较高右子树的右侧---右右&#xff1a;左单旋 代码 3. 新节点插入较高左子树的右侧---左右&#xff1a;先左单旋再右单旋 ​编辑 代码 4. 新节点插入较高右子树的左侧---右左&#xff1a;先…

如何选择适合大功率直流电子负载

选择适合大功率直流电子负载时&#xff0c;需要考虑以下几个关键因素&#xff1a; 功率范围&#xff1a;首先&#xff0c;需要确定所需的最大功率范围。大功率直流电子负载通常有不同的功率等级&#xff0c;如1kW、2kW、5kW等。根据实际应用场景和需求&#xff0c;选择合适的功…

CTF题型 php反序列化进阶(1) php原生类 例题和总结

CTF题型 php反序列化进阶(1) php原生文件操作类 例题和总结 文章目录 CTF题型 php反序列化进阶(1) php原生文件操作类 例题和总结特征原理 我们可以通过PHP自身本来就有的类来进行文件操作扫描目录的三个类DirectoryIterator(支持glob://协议)FilesystemIterator&#xff08;继…

基于springboot的stone音乐播放器的设计与实现

摘 要 随着我国经济的高速发展与人们生活水平的日益提高&#xff0c;人们对生活质量的追求也多种多样。尤其在人们生活节奏不断加快的当下&#xff0c;人们更趋向于足不出户解决生活上的问题&#xff0c;stone音乐播放器展现了其蓬勃生命力和广阔的前景。与此同时&#xff0c;…

使用 CSS 实现毛玻璃效果

在现代 Web 设计中,毛玻璃效果越来越受欢迎。它能够让界面元素看起来更加柔和、朦胧,同时又不会完全遮挡背景内容,给人一种透明而又不失质感的视觉体验。虽然过去实现这种效果需要借助图像编辑软件,但现在只需要几行 CSS 代码,就可以在网页上呈现出令人惊艳的毛玻璃效果。 使用…

小火星露谷管理器 报错:“你似乎没有安装Edge的webview2”

错误 解决办法 你可以到这个地方下载安装webview2 https://developer.microsoft.com/zh-cn/microsoft-edge/webview2/?formMT00IS

如何进行汇川PLCH1U-XP系列PLC远程监控?

在工业自动化的浪潮中&#xff0c;可编程逻辑控制器&#xff08;PLC&#xff09;作为控制系统的核心&#xff0c;其稳定性和可靠性对于生产流程的顺畅运行至关重要。汇川PLCH1U-XP系列以其高性能和广泛的应用场景&#xff0c;在工业控制领域占有一席之地。然而&#xff0c;对于…

华为机试真题练习汇总(81~90)

华为机试真题练习汇总&#xff08;81~90&#xff09; 华为机试真题练习汇总&#xff08;81~90&#xff09;HJ81 字符串字符匹配** HJ82 将真分数分解为埃及分数HJ83 二维数组操作HJ84 统计大写字母个数HJ85 最长回文子串HJ86 求最大连续bit数HJ87 密码强度等级* HJ88 扑克牌大小…

2024年 嵌入式系统设计师(中级)

2024年 嵌入式系统设计师全套视频、历年真题及解析、历年真题视频解析、教材、模拟题、重点笔记等资料 1、2023、2022、2021、2020年全套教程精讲视频。 2、嵌入式系统设计师历年真题及解析&#xff08;综合知识、案例分析&#xff09;、历年真题视频解析。 3、官方最新信息嵌…

【爬虫实战】使用Python获取花粉俱乐部中Mate60系列的用户发帖数据

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

每日一题 1969 数组元素的最小非零乘积

1969. 数组元素的最小非零乘积 题目描述&#xff1a; 给你一个正整数 p 。你有一个下标从 1 开始的数组 nums &#xff0c;这个数组包含范围 [1, 2p - 1] 内所有整数的二进制形式&#xff08;两端都 包含&#xff09;。你可以进行以下操作 任意 次&#xff1a; 从 nums 中选…

yolov7 gui 轻松通过GUI来实现车辆行人计数

YOLOv7 GUI 是一款用户友好型图形界面应用程序&#xff0c;专为简化基于YOLOv7&#xff08;You Only Look Once version 7&#xff09;的目标检测流程而设计。该工具允许用户无需深入掌握命令行操作和复杂编程细节&#xff0c;即可方便快捷地运行YOLOv7模型来检测图像或视频中的…

进制,码制及其表示范围

一 进制 1 常见的进制及其简写 十进制&#xff08;Dec&#xff09;二进制&#xff08;Binary&#xff09;十六进制&#xff08;Hex&#xff09;八进制&#xff08;Octal&#xff09; 2 进制之间的相互转换 二 码制 1 常用的码制 三 各码制在定点整数时表示的范围 个人推导…

使用Vscode连接云进行前端开发

使用Vscode连接云进行前端开发 1、ssh连接腾讯云 本人使用的是腾讯云。 然后vscode,用最新版&#xff0c;插件选择remote ssh&#xff0c;或者remote xxx下载过来。 然后点击远程资源管理器&#xff0c;选择SSH通道 然后输入命令如下。 ssh rootip然后输入密码 腾讯云应该…

网络工程师练习题2

网络工程师 将专用IP地址转换为公用IP地址的技术是&#xff08;&#xff09;。 A.ARPB.DHCPC.UTMD.NAT 【答案】D 【解析】概念题&#xff0c;NAT技术将源地址从内部专用地址转换成可以在外部Internet上路由的全局IP地址。 R1、R2是一个自治系统中采用RIP路由协议的两个相…

社交变革:探索Facebook的魔力

社交媒体平台的崛起已经改变了我们与世界的交互方式&#xff0c;而Facebook作为其中的巨头&#xff0c;其影响力和魔力更是不可忽视。本文将深入探讨Facebook如何引领社交变革&#xff0c;并探索其背后的魔力所在。 连接世界的纽带 Facebook的独特之处在于它作为一个社交平台&…