五、 QtDBus编程

本文详细介绍了如何使用Qt的D-Bus接口创建服务并注册对象,包括通过QDBusMessage和QDBusInterface访问服务的方法,以及如何从D-Bus XML自动生成代理类。此外,还探讨了使用Adapter注册Object的步骤,并展示了如何设置服务以实现自动启动。
摘要由CSDN通过智能技术生成


参考了 https://blog.51cto.com/quantfabric/2118468

1、创建服务并注册对象

test.h文件:

#ifndef TEST_H
#define TEST_H
#include <QObject>

class test: public QObject
{
    Q_OBJECT
    //定义Interface名称为com.scorpio.test.value
    Q_CLASSINFO("D-Bus Interface", "com.scorpio.test.value")
public:
    test(int value);

public slots:
    int maxValue();
    int minValue();
    int value();
private:
    int m_value;
};

#endif // TEST_H

test.cpp文件:

#include "test.h"

test::test(int value)
{
    m_value = value;
}

int test::maxValue()
{
    return 100;
}
int test::minValue()
{
    return 0;
}
int test::value()
{
    return m_value;
}

main.cpp文件:

#include <QCoreApplication>
#include <QDBusConnection>
#include <QDebug>
#include <QDBusError>
#include "test.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //建立到session bus的连接
    QDBusConnection connection = QDBusConnection::sessionBus();
    //在session bus上注册名为com.scorpio.test的服务
    if(!connection.registerService("com.scorpio.test"))
    {
        qDebug() << "error:" << connection.lastError().message();
        exit(-1);
    }
    test object(60);
    //注册名为/test/objects的对象,把类Object所有槽函数导出为object的method
    connection.registerObject("/test/objects", &object,QDBusConnection::ExportAllSlots);

    return a.exec();
}

启动程序后,在命令行打开qdbusviewer,查看session bus。
在这里插入图片描述
右侧双击Method方法会调用该方法。并打印日志在下面

2、通过QDBusMessage访问Service

确保com.scorpio.test服务运行在总线上。
编写一个控制台程序,使用消息访问com.scorpio.test服务。

#include <QCoreApplication>
#include <QDBusMessage>
#include <QDBusConnection>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    //构造一个method_call消息,服务名称为:com.scorpio.test,对象路径为:/test/objects
    //接口名称为com.scorpio.test.value,method名称为value
    QDBusMessage message = QDBusMessage::createMethodCall("com.scorpio.test",
                           "/test/objects",
                           "com.scorpio.test.value",
                           "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!";
    }

    return a.exec();
}

3、通过QDBusInterface 访问Service

编写一个控制台程序,使用接口访问com.scorpio.test服务。

#include <QCoreApplication>
#include <QDBusMessage>
#include <QDBusConnection>
#include <QDBusReply>
#include <QDBusInterface>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    // 创建QDBusInterface接口
    QDBusInterface interface("com.scorpio.test", "/test/objects",
                             "com.scorpio.test.value",
                             QDBusConnection::sessionBus());
    if (!interface.isValid())
    {
        qDebug() << qPrintable(QDBusConnection::sessionBus().lastError().message());
        exit(1);
    }
    //调用远程的value方法
    QDBusReply<int> reply = interface.call("value");
    if (reply.isValid())
    {
        int value = reply.value();
        qDebug() << QString("value =  %1").arg(value);
    }
    else
    {
        qDebug() << "value method called failed!";
    }

    return a.exec();
}

4、从D-Bus XML自动生成Proxy类

Proxy Object提供了一种更加直观的方式来访问Service,如同调用本地对象的方法一样。
生成Proxy类的流程如下:

A、使用工具qdbuscpp2xml从object.h生成XML文件;

qdbuscpp2xml -M test.h -o com.scorpio.test.xml
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
  <interface name="com.scorpio.test.value">
    <method name="maxValue">
      <arg type="i" direction="out"/>
    </method>
    <method name="minValue">
      <arg type="i" direction="out"/>
    </method>
    <method name="value">
      <arg type="i" direction="out"/>
    </method>
  </interface>
</node>

B、使用工具qdbusxml2cpp从XML文件生成继承自QDBusInterface的类

qdbusxml2cpp com.scorpio.test.xml -p valueInterface

生成两个文件:valueInterface.cpp和valueInterface.h
valueInterface.h文件:

/*
 * This file was generated by qdbusxml2cpp version 0.7
 * Command line was: qdbusxml2cpp com.scorpio.test.xml -p testInterface
 *
 * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
 *
 * This is an auto-generated file.
 * Do not edit! All changes made to it will be lost.
 */

#ifndef TESTINTERFACE_H_1526737677
#define TESTINTERFACE_H_1526737677

#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>

/*
 * Proxy class for interface com.scorpio.test.value
 */
class ComScorpioTestValueInterface: public QDBusAbstractInterface
{
    Q_OBJECT
public:
    static inline const char *staticInterfaceName()
    { return "com.scorpio.test.value"; }

public:
    ComScorpioTestValueInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);

    ~ComScorpioTestValueInterface();

public Q_SLOTS: // METHODS
    inline QDBusPendingReply<int> maxValue()
    {
        QList<QVariant> argumentList;
        return asyncCallWithArgumentList(QLatin1String("maxValue"), argumentList);
    }

    inline QDBusPendingReply<int> minValue()
    {
        QList<QVariant> argumentList;
        return asyncCallWithArgumentList(QLatin1String("minValue"), argumentList);
    }

    inline QDBusPendingReply<int> value()
    {
        QList<QVariant> argumentList;
        return asyncCallWithArgumentList(QLatin1String("value"), argumentList);
    }

Q_SIGNALS: // SIGNALS
};

namespace com {
  namespace scorpio {
    namespace test {
      typedef ::ComScorpioTestValueInterface value;
    }
  }
}
#endif

valueInterface.cpp文件:

/*
 * This file was generated by qdbusxml2cpp version 0.7
 * Command line was: qdbusxml2cpp com.scorpio.test.xml -p testInterface
 *
 * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
 *
 * This is an auto-generated file.
 * This file may have been hand-edited. Look for HAND-EDIT comments
 * before re-generating it.
 */

#include "testInterface.h"

/*
 * Implementation of interface class ComScorpioTestValueInterface
 */

ComScorpioTestValueInterface::ComScorpioTestValueInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
    : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
{
}

ComScorpioTestValueInterface::~ComScorpioTestValueInterface()
{
}

调用Proxy类访问Service如下:

#include <QCoreApplication>
#include <QDBusMessage>
#include <QDBusConnection>
#include <QDBusReply>
#include <QDBusInterface>
#include <QDebug>
#include "testInterface.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    // 初始化自动生成的Proxy类com::scorpio::test::value
    com::scorpio::test::value test("com.scorpio.test",
                                   "/test/objects",
                                   QDBusConnection::sessionBus());
    // 调用value方法
    QDBusPendingReply<int> reply = test.value();
    //qdbusxml2cpp生成的Proxy类是采用异步的方式来传递Message,
    //所以需要调用waitForFinished来等到Message执行完成
    reply.waitForFinished();
    if (reply.isValid())
    {
        int value = reply.value();
        qDebug() << QString("value =  %1").arg(value);
    }
    else
    {
        qDebug() << "value method called failed!";
    }

    return a.exec();
}

5、使用Adapter注册Object

可以直接把test类注册为消息总线上的一个Object,但QT4不推荐。QT4推荐使用Adapter来注册Object。
大多数情况下,可能只需要把自定义的类里的方法有选择的发布到消息总线上,使用Adapter可以很方便的实现选择性发布。
生成Adapter类的流程如下:

A、使用工具 qdbuscpp2xml从test.h生成XML文件
qdbuscpp2xml -M test.h -o com.scorpio.test.xml 
B、编辑com.scorpio.test.xml,选择需要发布的method,不需要发布的删除。
C、使用工具qdbusxml2cpp从XML文件生成继承自QDBusInterface的类
qdbusxml2cpp com.scorpio.test.xml -i test.h -a valueAdaptor

生成两个文件:valueAdaptor.cpp和valueAdaptor.h
valueAdaptor.h文件:

/*
 * This file was generated by qdbusxml2cpp version 0.7
 * Command line was: qdbusxml2cpp com.scorpio.test.xml -i test.h -a valueAdaptor
 *
 * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
 *
 * This is an auto-generated file.
 * This file may have been hand-edited. Look for HAND-EDIT comments
 * before re-generating it.
 */

#ifndef VALUEADAPTOR_H_1526742670
#define VALUEADAPTOR_H_1526742670

#include <QtCore/QObject>
#include <QtDBus/QtDBus>
#include "test.h"
class QByteArray;
template<class T> class QList;
template<class Key, class Value> class QMap;
class QString;
class QStringList;
class QVariant;

/*
 * Adaptor class for interface com.scorpio.test.value
 */
class ValueAdaptor: public QDBusAbstractAdaptor
{
    Q_OBJECT
    Q_CLASSINFO("D-Bus Interface", "com.scorpio.test.value")
    Q_CLASSINFO("D-Bus Introspection", ""
"  <interface name=\"com.scorpio.test.value\">\n"
"    <method name=\"maxValue\">\n"
"      <arg direction=\"out\" type=\"i\"/>\n"
"    </method>\n"
"    <method name=\"minValue\">\n"
"      <arg direction=\"out\" type=\"i\"/>\n"
"    </method>\n"
"  </interface>\n"
        "")
public:
    ValueAdaptor(QObject *parent);
    virtual ~ValueAdaptor();

public: // PROPERTIES
public Q_SLOTS: // METHODS
    int maxValue();
    int minValue();
Q_SIGNALS: // SIGNALS
};

#endif

valueAdaptor.cpp文件:

/*
 * This file was generated by qdbusxml2cpp version 0.7
 * Command line was: qdbusxml2cpp com.scorpio.test.xml -i test.h -a valueAdaptor
 *
 * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
 *
 * This is an auto-generated file.
 * Do not edit! All changes made to it will be lost.
 */

#include "valueAdaptor.h"
#include <QtCore/QMetaObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>

/*
 * Implementation of adaptor class ValueAdaptor
 */

ValueAdaptor::ValueAdaptor(QObject *parent)
    : QDBusAbstractAdaptor(parent)
{
    // constructor
    setAutoRelaySignals(true);
}

ValueAdaptor::~ValueAdaptor()
{
    // destructor
}

int ValueAdaptor::maxValue()
{
    // handle method call com.scorpio.test.value.maxValue
    int out0;
    QMetaObject::invokeMethod(parent(), "maxValue", Q_RETURN_ARG(int, out0));
    return out0;
}

int ValueAdaptor::minValue()
{
    // handle method call com.scorpio.test.value.minValue
    int out0;
    QMetaObject::invokeMethod(parent(), "minValue", Q_RETURN_ARG(int, out0));
    return out0;
}

调用Adaptor类注册Object对象如下:

#include <QCoreApplication>
#include <QDBusConnection>
#include <QDebug>
#include <QDBusError>
#include "test.h"
#include "valueAdaptor.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QDBusConnection connection = QDBusConnection::sessionBus();
    test object(60);
    //ValueAdaptor是qdbusxml2cpp生成的Adaptor类
    ValueAdaptor valueAdaptor(&object);
    if (!connection.registerService("com.scorpio.test"))
    {
        qDebug() << connection.lastError().message();
        exit(1);
    }
    connection.registerObject("/test/objects", &object);
    return a.exec();
}

使用qdbusviewer查看发布的method。
在这里插入图片描述

6、自动启动Service

D-Bus系统提供了一种机制可以在访问某个service时,自动把应用程序运行起来。
需要在/usr/share/dbus-1/services下面建立com.scorpio.test.service文件,文件的内容如下:

[D-BUS Service]
Name=com.scorpio.test
Exec=/path/to/scorpio/test

在访问test的method前,不必手动运行应用程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值