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 = 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 -"
        }
    }
}

在Linux下,QT可以使用mqueue消息队列实现进程通信。为了使用消息队列,需要包含头文件#include <mqueue.h>,并在pro文件中添加编译选项LIBS = -lrt。消息队列具有以下特征:可以设置最大消息个数和每个消息的最大字节数,可以向消息队列中写入多条消息,而其他进程读取一条消息后,消息队列就会删除这条消息。 要发送消息到消息队列中,可以使用mq_send函数。该函数的原型是int mq_send(mqd_t mqdes, const char *ptr, size_t len, unsigned int prio)。其中,mqdes是打开消息队列时返回的消息队列描述符,ptr是指向要发送的消息的指针,len是消息的长度,prio是消息的优先级。 在应用中使用消息队列进行进程通信,可以发现消息队列具有强大的功能。它可以方便地管理线程,实现互斥量和条件变量等功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Qt实现IPC进程通信-mqueue消息队列](https://blog.csdn.net/weixin_40355471/article/details/113178838)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [进程通信之深入消息队列的详解](https://download.csdn.net/download/weixin_38517212/14872197)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HX科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值