QT项目_RPC(进程间通讯)
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 = subdirsSUBDIRS += \apply \layer
apply/apply.pro
QT += quick \widgetsCONFIG += 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.0SOURCES += \main.cpp \mainwidget.cpp \rpc/MessageTip.cpp \rpc/RPCClient.cpp \rpc/RPCServer.cppRESOURCES += 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/msgpackHEADERS += \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)
{//todoqDebug() << "apply recv :" << value;
}void RPCServer::setApplystring(rpc_conn conn , std::string value)
{//todoqDebug() << "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.12Window {visible: truewidth: 640height: 480objectName: "apply_window"title: qsTr("Hello apply")signal window_interface(bool enable)Column{anchors.fill: parentspacing: 20Button{width: 140height: 50text: "开启界面2"onClicked: {window_interface(true)}}Mybutton{width: 140height: 300}}
}
apply/Mybutton.qml
import QtQuick 2.0
import QtQuick.Controls 2.12Item {objectName: "mybutton"signal applyvalueChanged(int value)signal applystringChanged(string value)Column{spacing: 10Button{objectName: "button"width: 140height: 50text: "send1"onClicked: {applyvalueChanged(1)}}Button{width: 140height: 50text: "send2"onClicked: {applyvalueChanged(2)}}Button{width: 140height: 50text: "验证string"onClicked: {applystringChanged("{\"name\":\"lili\",\"age\":24,\"class\":6}")}}}
}
layer.pro
QT += quick
QT += widgetsCONFIG += 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.0SOURCES += \main.cpp \mainwidget.cpp \rpc/MessageTip.cpp \rpc/RPCClient.cpp \rpc/RPCServer.cppRESOURCES += 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/msgpackHEADERS += \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);
//#elsem_pClient = new rest_rpc::rpc_client("127.0.0.1", 9001);
//#endifm_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)
{//todoMessageTip::setApplyvalue(value);qDebug() << "APPLY SEND :" << value;
}void RPCServer::layerstringChanged(rpc_conn conn , std::string value)
{//todoMessageTip::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.12Window {visible: truewidth: 640height: 480title: qsTr("Hello layer")Column{anchors.fill: parentspacing: 20Button{width: 140height: 50text: "layer +"}Button{width: 140height: 50text: "layer -"}}
}