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"的service
if (!bus.registerService("com.test.hotel")) {
qDebug() << bus.lastError().message();
exit(1);
}
//一定要用实例化这种形式,使用定义的方式不行
DBUSServer *dbusserver = new DBUSServer();
// 注册名为"/dbusserver"的object。
// "QDBusConnection::ExportAllSlots"表示把类DBUSServer的所有Slot都导出为这个Object的method
bus.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 = subdirs
SUBDIRS += \
apply \
layer
apply/apply.pro
QT += quick \
widgets \
dbus
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 += \
Dbusclass.cpp \
main.cpp \
mainwidget.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
HEADERS += \
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_OBJECT
public:
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"的service
if (!bus.registerService("com.test.apply")) {
qDebug() << bus.lastError().message();
exit(1);
}
//一定要用实例化这种形式,使用定义的方式不行
Dbusclass *dbusapply = new Dbusclass();
// 注册名为"/dbusserver"的object。
// "QDBusConnection::ExportAllSlots"表示把类DBUSServer的所有Slot都导出为这个Object的method
bus.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.12
Window {
visible: true
width: 640
height: 480
objectName: "apply_window"
title: qsTr("Hello apply")
signal window_interface(bool enable)
signal createSignal()
signal qDBusMessage()
signal qDBusInterface()
Column{
anchors.fill: parent
spacing: 20
Button{
width: 140
height: 50
text: "开启界面2"
onClicked: {
window_interface(true)
}
}
Button{
width: 140
height: 50
text: "createSignal_发布消息"
onClicked: {
createSignal()
}
}
Button{
width: 140
height: 50
text: "QDBusMessage"
onClicked: {
qDBusMessage()
}
}
Button{
width: 140
height: 50
text: "QDBusInterface"
onClicked: {
qDBusInterface()
}
}
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
QT += dbus
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 += \
dbusclass.cpp \
main.cpp \
mainwidget.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
HEADERS += \
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"的service
if (!bus.registerService("com.test.layer")) {
qDebug() << bus.lastError().message();
exit(1);
}
//一定要用实例化这种形式,使用定义的方式不行
Dbusclass *dbusclass = new Dbusclass();
// 注册名为"/dbuslayer"的object。
// "QDBusConnection::ExportAllSlots"表示把类DBUSServer的所有Slot都导出为这个Object的method
bus.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.12
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello layer")
signal createSignal()
signal qDBusMessage()
signal qDBusInterface()
Column{
anchors.fill: parent
spacing: 20
Button{
width: 140
height: 50
text: "createSignal_发布消息"
onClicked: {
createSignal()
}
}
Button{
width: 140
height: 50
text: "QDBusMessage"
onClicked: {
qDBusMessage()
}
}
Button{
width: 140
height: 50
text: "QDBusInterface"
onClicked: {
qDBusInterface()
}
}
}
}