Qt Remote Objects(QRO)是Qt提供的一种用于实现远程对象通信的机制。
QtRO支持两种类型的通信:RPC(远程过程调用)和LPC(本地进程通信)。
RPC(远程过程调用)包括以下几种类型:
基于HTTP协议的RPC:例如Dubbo、Thrift等。
基于二进制协议的RPC:例如GRPC、Hetty等。
基于TCP协议的RPC:例如RMI、Remoting等。
LPC包括基于共享内存的通信和基于消息传递的通信。
总的来说,QtRO类似于平时的socket通信、串口通信、信号槽通信。它最大的特点是集合了这些通信的功能,使得远端通信能与本机通信一样使用信号槽的方式来收发信息
以下是我的文件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))
}
QT += remoteobjects
REPC_SOURCE += \
interface.rep
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);
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include
#include "commoninterface.h"
#include
#include
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
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
#include
#include
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();
}
}
pro:
QT += remoteobjects
REPC_REPLICA += \
interface.rep
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include "rep_interface_replica.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
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
#include
#include
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();
}
}
1.基本数据类型:如int、bool、char、float、double等。
2.Qt的核心类:如QString、QList、QMap等。
3.Qt的自定义类:只要这些类实现了序列化功能,就可以作为信号参数。
m_pHost->setHostUrl(QUrl("tcp://192.168.137.100:8081"));
只有在服务端和客户端均用Qt开发的时候,适合使用QtRO方式。使用QtRO使得接口定义和实现更加方便。当已经有服务端程序,仅用Qt编写客户端时,就无法使用QtRO了。