QT_dbus(ipc进程间通讯)
QT_dbus(ipc进程间通讯)
前言:
参考链接:
https://www.cnblogs.com/brt3/p/9614899.html
https://blog.csdn.net/weixin_43246170/article/details/120994311
https://blog.csdn.net/kchmmd/article/details/118605315
一个大型项目可能需要多个子程序同时运行,但是子程序之间的通讯就需要进程间通讯,DBUS是QT自带的组件,尝试使用一下。
1、创建包含多个子程序的工程
TEMPLATE = subdirs
2、第一个dbus试验:先建立session bus的连接,然后使用QT自带工具qdbusviewer演示使用
#include "mainwidget.h"
#include "qdebug.h"
#include "dbus/RPCClient.h"
#include "dbus/DBUSServer.h"
#include "dbus/MessageTip.h"
#include <QProcess>#include <QtDBus/QtDBus>
#include <QDBusError>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;}// 用于建立到session bus的连接QDBusConnection bus = QDBusConnection::sessionBus();// 在session bus上注册名为"com.test.hotel"的serviceif (!bus.registerService("com.test.hotel")) {qDebug() << bus.lastError().message();exit(1);}//一定要用实例化这种形式,使用定义的方式不行DBUSServer *dbusserver = new DBUSServer();// 注册名为"/dbusserver"的object。// "QDBusConnection::ExportAllSlots"表示把类DBUSServer的所有Slot都导出为这个Object的methodbus.registerObject("/dbusserver", dbusserver, QDBusConnection::ExportAllSlots);//bus.registerObject("/dbusserver", dbusserver, QDBusConnection::ExportAllSignal);
}
DBUSServer.cpp
#include "DBUSServer.h"
#include "qdebug.h"DBUSServer::DBUSServer()
{connect(this, SIGNAL(opendoor()), this, SLOT(onopenlight()));
}void DBUSServer::oncheckIn()
{qDebug() << "checkIn";emit opendoor();
}
void DBUSServer::oncheckOut()
{qDebug() << "oncheckOut";
}
void DBUSServer::onopenlight()
{qDebug() << "onopenlight";
}
int DBUSServer::onquery()
{return 50;
}
DBUSServer.h
#ifndef DBUSSERVER_H
#define DBUSSERVER_H
#include <QObject>
#include <QBrush>
class DBUSServer : public QObject
{Q_OBJECT
public:DBUSServer();public slots:void oncheckIn();void oncheckOut();int onquery();void onopenlight();signals:// Check in,参数为房间数,返回成功拿到的房间数void opendoor();private:int m_rooms;//QReadWriteLock m_lock;};
#endif // RPCSERVER_H
3、综合试验,经过几天的研究,决定以后采用下面的方法来进行进程间通讯
方法一:
说明:类似信号和槽(我个人认为是类似于MQTT协议的订阅和发布机制),
//函数说明:在不同进程之间建立信号和槽的关系,"on_hello"是自定义的信号的名(也可认为是发布的主题)
//参数1:服务器地址,参数2:路径(不填),参数3:Interface名称(不填),参数4:自定义信号(可认为是订阅信号),参数5:槽函数所在的对象,参数6:槽函数
QDBusConnection::sessionBus().connect("com.test.hotel", "", "", "on_hello", this, SLOT(onApplyvalueChanged(int)));//函数说明:真正发布消息的地方,只要是和"on_hello"建立连接的槽函数都会得到相应
QDBusMessage msg = QDBusMessage::createSignal("/dbusserver", "com.test.hotel", "on_hello");
msg << 456; //如果带参数就这样加上要传的参数
QDBusConnection::sessionBus().send(msg);
方法二:
说明:这种方法虽然思路清晰,但是调用一次函数代码量比较多,不是太推荐
//参数1:服务器地址,参数2:路径,参数3:Interface名称,参数4:调用槽函数的名字
QDBusMessage message = QDBusMessage::createMethodCall("com.test.hotel","/dbusserver","com.test.hotel.show","oncheckIn");
//槽函数有几种情况:①有参数传入无参数返回,②有参数传入有参数返回,③无参数传入有参数返回
/*有参数传入有参数返回*/
message << 123;//给int oncheckIn(int value);这个槽函数传入的参数(如果没有参数需要传,此步骤不用写)
//发送消息并获取返回值
QDBusMessage response = QDBusConnection::sessionBus().call(message);
//判断method是否被正确返回
if (response.type() == QDBusMessage::ReplyMessage)
{//从返回参数获取返回值int value = response.arguments().takeFirst().toInt();qDebug() << QString("value = %1").arg(value);
}
else
{qDebug() << "value method called failed!";
}/*有参数传入无参数返回*/
message << 123;//给int oncheckIn(int value);这个槽函数传入的参数(如果没有参数需要传,此步骤不用写)
//发送消息
QDBusMessage response = QDBusConnection::sessionBus().call(message);
//判断method是否被正确返回
if (response.type() == QDBusMessage::ReplyMessage)
{qDebug() << "value method called successfull";
}
else
{qDebug() << "value method called failed!";
}/*无参数传入无参数返回*/
//发送消息
QDBusMessage response = QDBusConnection::sessionBus().call(message);
//判断method是否被正确返回
if (response.type() == QDBusMessage::ReplyMessage)
{qDebug() << "value method called successfull";
}
else
{qDebug() << "value method called failed!";
}
方法三:
说明:这种方法虽然思路清晰,比方法二更简介一些,推荐使用
//参数1:服务器地址,参数2:路径,参数3:Interface名称
QDBusInterface interface("com.test.hotel", "/dbusserver", "com.test.hotel.show", QDBusConnection::sessionBus());
if (!interface.isValid()) {qDebug() << "dbus interface fail";return;
}
QDBusMessage response;
//调用槽函数分为三种:①有参数传入无参数返回,②有参数传入有参数返回,③无参数传入有参数返回
//response = interface.call("onquery", 158);//有参数传入有参数返回
response = interface.call("onquery");//无参数传入有参数返回/有参数传入无参数返回
//判断method是否被正确返回
if (response.type() == QDBusMessage::ReplyMessage) {//从返回参数获取返回值(没有返回值的返回0,有返回值的正常返回)int value = response.arguments().takeFirst().toInt();qDebug() << QString("value = %1").arg(value);
}
else
{qDebug() << "value method called failed!";
}
工程源码展示:
test_rpc.pro
TEMPLATE = subdirsSUBDIRS += \\apply \\layer
apply/apply.pro
QT += quick \\widgets \\dbusCONFIG += 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 += \\Dbusclass.cpp \\main.cpp \\mainwidget.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 += targetHEADERS += \\Dbusclass.h \\mainwidget.h
apply/Headers/Dbusclass.h
#ifndef DBUSCLASS_H
#define DBUSCLASS_H
#include <QObject>
#include <QBrush>
class Dbusclass : public QObject
{Q_OBJECT//定义Interface名称为:"com.test.hotel.show"Q_CLASSINFO("D-Bus Interface", "com.test.apply.show")
public:Dbusclass();public slots:int oncheckIn(int value);//有参数传入有参数返回void oncheckOut(int value);//有参数传入无参数返回int onquery();//无参数传入有参数返回void onopenlight();//无参数传入无参数返回signals:void opendoor();private:int m_rooms;
};
#endif // RPCSERVER_H
apply/Headers/mainwidget.h
#ifndef MAINWIDGET_H
#define MAINWIDGET_H#include <QObject>
#include <QWidget>
#include <QQmlComponent>
#include <QQmlApplicationEngine>
#include <QQuickItem>
#include "Dbusclass.h"class MainWidget : public QObject
{Q_OBJECTpublic:MainWidget();protected slots:void onClickPageNo(bool enable);void onApplyvalueChanged(int value);void onApplystringChanged(QString value);void oncreateSignal();void onqDBusMessage();void onqDBusInterface();private:QQuickItem *m_applyItem = nullptr;QObject *m_applyObject = nullptr;
};#endif // MAINWIDGET_H
apply/Sources/Dbusclass.cpp
#include "Dbusclass.h"
#include "qdebug.h"
#include <QDebug>Dbusclass::Dbusclass()
{connect(this, SIGNAL(opendoor()), this, SLOT(onopenlight()));
}int Dbusclass::oncheckIn(int value)
{qDebug() << "checkIn:" << value;emit opendoor();return value;
}
void Dbusclass::oncheckOut(int value)
{qDebug() << "oncheckOut:" << value;
}
void Dbusclass::onopenlight()
{qDebug() << "onopenlight";
}
int Dbusclass::onquery()
{return 50;
}
apply/Sources/mainwidget.cpp
#include "mainwidget.h"
#include "qdebug.h"
#include "Dbusclass.h"
#include <QProcess>#include <QtDBus/QtDBus>
#include <QDBusError>
#include <QDBusMessage>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)));connect(mainObject, SIGNAL(createSignal()), this, SLOT(oncreateSignal()));connect(mainObject, SIGNAL(qDBusMessage()), this, SLOT(onqDBusMessage()));connect(mainObject, SIGNAL(qDBusInterface()), this, SLOT(onqDBusInterface()));// 用于建立到session bus的连接QDBusConnection bus = QDBusConnection::sessionBus();// 在session bus上注册名为"com.test.hotel"的serviceif (!bus.registerService("com.test.apply")) {qDebug() << bus.lastError().message();exit(1);}//一定要用实例化这种形式,使用定义的方式不行Dbusclass *dbusapply = new Dbusclass();// 注册名为"/dbusserver"的object。// "QDBusConnection::ExportAllSlots"表示把类DBUSServer的所有Slot都导出为这个Object的methodbus.registerObject("/dbusapply", dbusapply, QDBusConnection::ExportAllSlots);//bus.registerObject("/dbusapply", dbusapply, QDBusConnection::ExportAllSignal);//参数1:服务器地址,参数2:路径,参数3:Interface名称(不填),参数4:自定义信号(可认为是订阅信号),参数5:槽函数所在的对象,参数6:槽函数QDBusConnection::sessionBus().connect("com.test.layer", "", "", "on_layer", this, SLOT(onApplyvalueChanged(int)));
}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;
}void MainWidget::onApplystringChanged(QString value)
{qDebug() << "onApplystringChanged" << value;
}void MainWidget::oncreateSignal()
{qDebug() << "oncreateSignal" ;QDBusMessage msg = QDBusMessage::createSignal("/dbuslayer", "com.test.layer.show", "on_apply");msg << 456;QDBusConnection::sessionBus().send(msg);
}void MainWidget::onqDBusMessage()
{qDebug() << "onqDBusMessage" ;QDBusMessage message = QDBusMessage::createMethodCall("com.test.layer","/dbuslayer","com.test.layer.show","oncheckIn");message << 234;//发送消息QDBusMessage response = QDBusConnection::sessionBus().call(message);//判断method是否被正确返回if (response.type() == QDBusMessage::ReplyMessage) {//从返回参数获取返回值int value = response.arguments().takeFirst().toInt();qDebug() << QString("value = %1").arg(value);} else {qDebug() << "value method called failed!";}
}void MainWidget::onqDBusInterface()
{qDebug() << "onqDBusInterface" ;QDBusInterface interface("com.test.layer", "/dbuslayer", "com.test.layer.show", QDBusConnection::sessionBus());if (!interface.isValid()) {qDebug() << "dbus interface fail";return;}QDBusMessage response;response = interface.call("oncheckIn", 158); // 有参数//判断method是否被正确返回if (response.type() == QDBusMessage::ReplyMessage) {//从返回参数获取返回值int value = response.arguments().takeFirst().toInt();qDebug() << QString("value = %1").arg(value);} else {qDebug() << "value method called failed!";}
}
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/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)signal createSignal()signal qDBusMessage()signal qDBusInterface()Column{anchors.fill: parentspacing: 20Button{width: 140height: 50text: "开启界面2"onClicked: {window_interface(true)}}Button{width: 140height: 50text: "createSignal_发布消息"onClicked: {createSignal()}}Button{width: 140height: 50text: "QDBusMessage"onClicked: {qDBusMessage()}}Button{width: 140height: 50text: "QDBusInterface"onClicked: {qDBusInterface()}}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 += widgets
QT += dbusCONFIG += 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 += \\dbusclass.cpp \\main.cpp \\mainwidget.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 += targetHEADERS += \\dbusclass.h \\mainwidget.h
layer/Herders/dbusclass.h
#ifndef DBUSCLASS_H
#define DBUSCLASS_H#include <QObject>class Dbusclass : public QObject
{Q_OBJECT//定义Interface名称为:"com.test.layer.show"Q_CLASSINFO("D-Bus Interface", "com.test.layer.show")
public:Dbusclass();public slots:int oncheckIn(int value);//有参数传入有参数返回
};#endif // DBUSCLASS_H
layer/Herders/mainwidget.h
#ifndef MAINWIDGET_H
#define MAINWIDGET_H#include <QObject>
#include <QQmlComponent>
#include <QQmlApplicationEngine>
#include <QQuickItem>class mainwidget : public QObject
{Q_OBJECT
public:mainwidget();public slots:void oncreateSignal();void onqDBusMessage();void onqDBusInterface();void onMessage_recv(int num);private:
};#endif // MAINWIDGET_H
layer/Sources/dbusclass.cpp
#include "dbusclass.h"
#include <QDebug>Dbusclass::Dbusclass()
{}int Dbusclass::oncheckIn(int value)
{qDebug() << "checkIn:" << value;return value;
}
layer/Sources/mainwidget.cpp
#include "mainwidget.h"
#include "dbusclass.h"
#include <QDBusMessage>
#include <QDBusConnection>
#include <QDBusInterface>
#include <QtDBus/QtDBus>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;}// 用于建立到session bus的连接QDBusConnection bus = QDBusConnection::sessionBus();// 在session bus上注册名为"com.test.hotel"的serviceif (!bus.registerService("com.test.layer")) {qDebug() << bus.lastError().message();exit(1);}//一定要用实例化这种形式,使用定义的方式不行Dbusclass *dbusclass = new Dbusclass();// 注册名为"/dbuslayer"的object。// "QDBusConnection::ExportAllSlots"表示把类DBUSServer的所有Slot都导出为这个Object的methodbus.registerObject("/dbuslayer", dbusclass, QDBusConnection::ExportAllSlots);connect(mainObject, SIGNAL(createSignal()), this, SLOT(oncreateSignal()));connect(mainObject, SIGNAL(qDBusMessage()), this, SLOT(onqDBusMessage()));connect(mainObject, SIGNAL(qDBusInterface()), this, SLOT(onqDBusInterface()));QDBusConnection::sessionBus().connect("com.test.apply", "", "", "on_apply", this, SLOT(onMessage_recv(int)));
}void mainwidget::oncreateSignal()
{qDebug() << "oncreateSignal";QDBusMessage msg = QDBusMessage::createSignal("/dbusapply", "com.test.apply.show", "on_layer");msg << 123;QDBusConnection::sessionBus().send(msg);
}void mainwidget::onqDBusMessage()
{qDebug() << "onLayer_reduce";QDBusMessage message = QDBusMessage::createMethodCall("com.test.apply","/dbusapply","com.test.apply.show","oncheckIn");message << 234;//发送消息QDBusMessage response = QDBusConnection::sessionBus().call(message);//判断method是否被正确返回if (response.type() == QDBusMessage::ReplyMessage) {//从返回参数获取返回值int value = response.arguments().takeFirst().toInt();qDebug() << QString("value = %1").arg(value);} else {qDebug() << "value method called failed!";}
}void mainwidget::onqDBusInterface()
{qDebug() << "onLayer_reduce";QDBusInterface interface("com.test.apply", "/dbusapply", "com.test.apply.show", QDBusConnection::sessionBus());if (!interface.isValid()) {qDebug() << "dbus interface fail";return;}QDBusMessage response;response = interface.call("oncheckIn", 158); // 有参数
// response = interface.call("oncheckOut"); // 无参数
// response = interface.call("onopenlight");//判断method是否被正确返回if (response.type() == QDBusMessage::ReplyMessage) {//从返回参数获取返回值int value = response.arguments().takeFirst().toInt();qDebug() << QString("value = %1").arg(value);} else {qDebug() << "value method called failed!";}
}void mainwidget::onMessage_recv(int num)
{qDebug() << "onMessage_recv:" << num;
}
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/main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12Window {visible: truewidth: 640height: 480title: qsTr("Hello layer")signal createSignal()signal qDBusMessage()signal qDBusInterface()Column{anchors.fill: parentspacing: 20Button{width: 140height: 50text: "createSignal_发布消息"onClicked: {createSignal()}}Button{width: 140height: 50text: "QDBusMessage"onClicked: {qDBusMessage()}}Button{width: 140height: 50text: "QDBusInterface"onClicked: {qDBusInterface()}}}
}