QT项目_RPC(进程间通讯)
前言:
两个进程间通信、或是说两个应用程序之间通讯。实际情况是在QT开发的一个项目中,里面包含两个子程序,子程序有单独的界面和应用逻辑,这两个子程序跑起来之后需要一些数据的交互,例如:一个程序是用户界面和用户程序,另一个程序时OSD菜单
注意:RPC通讯传输的数据类型有bool、int和std::string(QString不行)
效果演示:
1、移植RCP源码到自己工程
①移植RPC,说白了就是两个文件夹里面有N多个源文件,直接复制过来直接用,需要自行修改.pro文件以便加入编译
# rest_rpc
INCLUDEPATH += $$PWD/msgpack
DEPENDPATH += $$PWD/msgpack
②工程目录
2、源码展示
test_rpc.pro
TEMPLATE = subdirs
SUBDIRS += \
apply \
layer
apply/apply.pro
QT += quick \
widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Refer to the documentation for the
# deprecated API to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwidget.cpp \
rpc/MessageTip.cpp \
rpc/RPCClient.cpp \
rpc/RPCServer.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
# rest_rpc
INCLUDEPATH += $$PWD/msgpack
DEPENDPATH += $$PWD/msgpack
HEADERS += \
mainwidget.h \
rpc/MessageTip.h \
rpc/RPCClient.h \
rpc/RPCServer.h
apply/Headers/rpc/MessageTip.h
#ifndef MESSAGETIP_H
#define MESSAGETIP_H
#include <qstring.h>
namespace MessageTip
{
void onApplyvalueChanged(int value);
void onApplystringChanged(std::string value);
}
#endif // MESSAGETIP_H
apply/Headers/rpc/RPCClient.h
#ifndef RPCCLIENT_H
#define RPCCLIENT_H
#include "rest_rpc/rpc_client.hpp"
class RPCClient
{
public:
RPCClient();
static RPCClient *get_instance()
{
static RPCClient manage;
return &manage;
}
/**
* @brief 尝试连接RPC Server
* @return true 连接成功,false 连接失败
*/
void tryConnect();
rest_rpc::rpc_client *getSocketObject();
private:
rest_rpc::rpc_client *m_pClient = nullptr;
};
#endif // RPCCLIENT_H
apply/Headers/rpc/RPCServer.h
#ifndef RPCSERVER_H
#define RPCSERVER_H
#include <qstring.h>
#include "rest_rpc/rpc_server.h"
using namespace rest_rpc;
using namespace rpc_service;
class RPCServer
{
public:
RPCServer();
void setApplyvalue(rpc_conn conn , int value);
void setApplystring(rpc_conn conn , std::string value);
};
#endif // RPCSERVER_H
apply/Headers/mainwidget.h
#ifndef MAINWIDGET_H
#define MAINWIDGET_H
#include <QObject>
#include <QWidget>
#include <QQmlComponent>
#include <QQmlApplicationEngine>
#include <QQuickItem>
#include "rpc/RPCServer.h"
class MainWidget : public QObject
{
Q_OBJECT
public:
MainWidget();
protected slots:
void onClickPageNo(bool enable);
void onApplyvalueChanged(int value);
void onApplystringChanged(QString value);
private:
QQuickItem *m_applyItem = nullptr;
QObject *m_applyObject = nullptr;
RPCServer *m_pRPCServer = nullptr;
};
#endif // MAINWIDGET_H
apply/Sources/rpc/MessageTip.cpp
#include "MessageTip.h"
#include "RPCClient.h"
#include "qdebug.h"
void MessageTip::onApplyvalueChanged(int value)
{
try {
RPCClient::get_instance()->getSocketObject()->call<void>("MessageTip::layervalueChanged", value);
} catch (const std::exception &e) {
qDebug() << "Exception {}", e.what();
}
}
void MessageTip::onApplystringChanged(std::string value)
{
try {
RPCClient::get_instance()->getSocketObject()->call<void>("MessageTip::layerstringChanged", value);
} catch (const std::exception &e) {
qDebug() << "Exception {}", e.what();
}
}
apply/Sources/rpc/RPCClient.cpp
#include "RPCClient.h"
#include <QtDebug>
RPCClient::RPCClient()
{
}
void RPCClient::tryConnect()
{
m_pClient = new rest_rpc::rpc_client("127.0.0.1", 9000);
m_pClient->enable_auto_reconnect(true);
m_pClient->connect();
std::thread([&] {
while (true)
{
if (m_pClient->has_connected()) {
qDebug() << "apply RPC connect success";
break;
} else {
qDebug() << "apply RPC connect fail";
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
}
}).detach();
}
rest_rpc::rpc_client *RPCClient::getSocketObject()
{
return m_pClient;
}
apply/Sources/rpc/RPCServer.cpp
#include "RPCServer.h"
#include "qdebug.h"
RPCServer::RPCServer()
{
std::thread([&] {
rpc_server server(9001, std::thread::hardware_concurrency());
server.register_handler("MessageTip::setApplyvalue", &RPCServer::setApplyvalue, this);
server.register_handler("MessageTip::setApplystring", &RPCServer::setApplystring, this);
server.run();
}).detach();
}
void RPCServer::setApplyvalue(rpc_conn conn , int value)
{
//todo
qDebug() << "apply recv :" << value;
}
void RPCServer::setApplystring(rpc_conn conn , std::string value)
{
//todo
qDebug() << "apply recv :" << QString::fromStdString(value);
}
apply/Sources/main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "mainwidget.h"
#include "qdebug.h"
#include "qthread.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
// QQmlApplicationEngine engine;
// const QUrl url(QStringLiteral("qrc:/main.qml"));
// QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
// &app, [url](QObject * obj, const QUrl & objUrl) {
// if (!obj && url == objUrl) {
// QCoreApplication::exit(-1);
// }
// }, Qt::QueuedConnection);
// engine.load(url);
MainWidget mainwidget;
return app.exec();
}
apply/Sources/mainwidget.cpp
#include "mainwidget.h"
#include "qdebug.h"
#include "rpc/RPCClient.h"
#include "rpc/MessageTip.h"
#include <QProcess>
MainWidget::MainWidget()
{
QQmlApplicationEngine *m_pEngine = new QQmlApplicationEngine;
QQmlComponent component(m_pEngine, QUrl(QStringLiteral("qrc:/main.qml")));
QObject *mainObject = component.create();
if (mainObject == nullptr) {
qDebug() << "mainObject fail";
return;
}
QList<QObject *> objectList = mainObject->findChildren<QObject *>("mybutton");
if (objectList.isEmpty()) {
qDebug() << "mybutton failed\n";
return;
}
m_applyObject = objectList.last();
connect(m_applyObject, SIGNAL(applyvalueChanged(int)), this, SLOT(onApplyvalueChanged(int)));
connect(m_applyObject, SIGNAL(applystringChanged(QString)), this, SLOT(onApplystringChanged(QString)));
connect(mainObject, SIGNAL(window_interface(bool)), this, SLOT(onClickPageNo(bool)));
m_pRPCServer = new RPCServer();
RPCClient::get_instance()->tryConnect();
}
void MainWidget::onClickPageNo(bool enable)
{
QProcess *process = new QProcess();
process->start("/home/zhou/work/test/build-test_rpc-Desktop_Qt_5_14_2_GCC_64bit-Debug/layer/layer");
}
void MainWidget::onApplyvalueChanged(int value)
{
qDebug() << "onApplyvalueChanged" << value;
MessageTip::onApplyvalueChanged(value);
}
void MainWidget::onApplystringChanged(QString value)
{
qDebug() << "onApplystringChanged" << value;
MessageTip::onApplystringChanged(std::string(value.toLocal8Bit()));
}
apply/main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
visible: true
width: 640
height: 480
objectName: "apply_window"
title: qsTr("Hello apply")
signal window_interface(bool enable)
Column{
anchors.fill: parent
spacing: 20
Button{
width: 140
height: 50
text: "开启界面2"
onClicked: {
window_interface(true)
}
}
Mybutton{
width: 140
height: 300
}
}
}
apply/Mybutton.qml
import QtQuick 2.0
import QtQuick.Controls 2.12
Item {
objectName: "mybutton"
signal applyvalueChanged(int value)
signal applystringChanged(string value)
Column{
spacing: 10
Button{
objectName: "button"
width: 140
height: 50
text: "send1"
onClicked: {
applyvalueChanged(1)
}
}
Button{
width: 140
height: 50
text: "send2"
onClicked: {
applyvalueChanged(2)
}
}
Button{
width: 140
height: 50
text: "验证string"
onClicked: {
applystringChanged("{\"name\":\"lili\",\"age\":24,\"class\":6}")
}
}
}
}
layer.pro
QT += quick
QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Refer to the documentation for the
# deprecated API to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwidget.cpp \
rpc/MessageTip.cpp \
rpc/RPCClient.cpp \
rpc/RPCServer.cpp
RESOURCES += qml.qrc
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
# rest_rpc
INCLUDEPATH += $$PWD/msgpack
DEPENDPATH += $$PWD/msgpack
HEADERS += \
mainwidget.h \
rpc/MessageTip.h \
rpc/RPCClient.h \
rpc/RPCServer.h
layer/Headers/rpc/MessageTip.h
#ifndef MESSAGETIP_H
#define MESSAGETIP_H
#include <qstring.h>
namespace MessageTip
{
void setApplyvalue(int value);
void setApplystring(std::string value);
}
#endif // MESSAGETIP_H
layer/Headers/rpc/RPCClient.h
#ifndef RPCCLIENT_H
#define RPCCLIENT_H
#include "rest_rpc/rpc_client.hpp"
class RPCClient
{
public:
RPCClient();
static RPCClient *get_instance()
{
static RPCClient layer_manage;
return &layer_manage;
}
/**
* @brief 尝试连接RPC Server
* @return true 连接成功,false 连接失败
*/
void tryConnect();
rest_rpc::rpc_client *getSocketObject();
private:
rest_rpc::rpc_client *m_pClient = nullptr;
};
#endif // RPCCLIENT_H
layer/Headers/rpc/RPCServer.h
#ifndef RPCSERVER_H
#define RPCSERVER_H
#include <QtDebug>
#include <QThread>
#include <QObject>
#include <QQuickItem>
#include "rest_rpc/rpc_server.h"
using namespace rest_rpc;
using namespace rpc_service;
class RPCServer : public QObject
{
Q_OBJECT
public:
explicit RPCServer(QObject *parent = nullptr);
void layervalueChanged(rpc_conn conn , int value);
void layerstringChanged(rpc_conn conn , std::string value);
protected:
signals:
private:
QObject *m_pMainObject = nullptr;
QQuickItem *m_pOSDAreaItem = nullptr;
};
#endif // RPCSERVER_H
layer/Headers/mainwidget.h
#ifndef MAINWIDGET_H
#define MAINWIDGET_H
#include <QObject>
#include <QQmlComponent>
#include <QQmlApplicationEngine>
#include <QQuickItem>
#include "rpc/RPCServer.h"
class mainwidget : public QObject
{
Q_OBJECT
public:
mainwidget();
private:
RPCServer *m_pRPCServer = nullptr;
};
#endif // MAINWIDGET_H
layer/Sources/rpc/MessageTip.cpp
#include "MessageTip.h"
#include "RPCClient.h"
#include <QtDebug>
void MessageTip::setApplyvalue(int value)
{
try {
return RPCClient::get_instance()->getSocketObject()->call<void>("MessageTip::setApplyvalue", value);
} catch (const std::exception &e) {
qDebug() << "setImageRotate exception" << e.what();
}
}
void MessageTip::setApplystring(std::string value)
{
try {
return RPCClient::get_instance()->getSocketObject()->call<void>("MessageTip::setApplystring", value);
} catch (const std::exception &e) {
qDebug() << "setImageRotate exception" << e.what();
}
}
layer/Sources/rpc/RPCClient.cpp
#include "RPCClient.h"
#include <QtDebug>
RPCClient::RPCClient()
{
}
void RPCClient::tryConnect()
{
//#if defined(__x86_64)
// m_pClient = new rest_rpc::rpc_client("192.168.31.95", 9001);
//#else
m_pClient = new rest_rpc::rpc_client("127.0.0.1", 9001);
//#endif
m_pClient->enable_auto_heartbeat(true);
m_pClient->connect();
std::thread([&] {
while (true)
{
qDebug() << "layer RPC connect fail";
if (m_pClient->has_connected()) {
qDebug() << "layer RPC connect success";
break;
} else {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
qDebug() << "layer RPC connect fail";
}
}
}).detach();
}
rest_rpc::rpc_client *RPCClient::getSocketObject()
{
return m_pClient;
}
layer/Sources/rpc/RPCServer.cpp
#include "RPCServer.h"
#include "rpc/MessageTip.h"
RPCServer::RPCServer(QObject *parent) : QObject(parent)
{
QThread::create([&] {
rpc_server server(9000, std::thread::hardware_concurrency());
server.register_handler("MessageTip::layervalueChanged", &RPCServer::layervalueChanged, this);
server.register_handler("MessageTip::layerstringChanged", &RPCServer::layerstringChanged, this);
server.run();
})->start();
qDebug() << "start rpc server";
}
void RPCServer::layervalueChanged(rpc_conn conn , int value)
{
//todo
MessageTip::setApplyvalue(value);
qDebug() << "APPLY SEND :" << value;
}
void RPCServer::layerstringChanged(rpc_conn conn , std::string value)
{
//todo
MessageTip::setApplystring(value);
qDebug() << "APPLY SEND :" << QString::fromStdString(value);
}
layer/Sources/main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "qdebug.h"
#include "mainwidget.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
// QQmlApplicationEngine engine;
// const QUrl url(QStringLiteral("qrc:/main.qml"));
// QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
// &app, [url](QObject * obj, const QUrl & objUrl) {
// if (!obj && url == objUrl) {
// QCoreApplication::exit(-1);
// }
// }, Qt::QueuedConnection);
// engine.load(url);
mainwidget mainwidget;
return app.exec();
}
layer/Sources/mainwidget.cpp
#include "mainwidget.h"
#include "rpc/RPCClient.h"
mainwidget::mainwidget()
{
QQmlApplicationEngine *m_pEngine = new QQmlApplicationEngine;
QQmlComponent component(m_pEngine, QUrl(QStringLiteral("qrc:/main.qml")));
QObject *mainObject = component.create();
if (mainObject == nullptr) {
qDebug() << "mainObject fail";
return;
}
m_pRPCServer = new RPCServer();
RPCClient::get_instance()->tryConnect();
}
layer/main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello layer")
Column{
anchors.fill: parent
spacing: 20
Button{
width: 140
height: 50
text: "layer +"
}
Button{
width: 140
height: 50
text: "layer -"
}
}
}