1.参考内容
https://blog.csdn.net/qq_41673920/article/details/121227229?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163756916716780264098531%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=163756916716780264098531&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-7-121227229.pc_search_result_control_group&utm_term=qt%E4%B8%AD%E7%9A%84qdbus&spm=1018.2226.3001.4187
一、DBus简介
DBus提供了一种低延时,低开销,高可用性的进程间通信方式,其以消息作为驱动,采用二进制的协议,实现一对一及多对多的对等通信,避免通信的序列化(编码过程)过程,提高通信效率.DBus进程通信的核心是提供了一个后台中转守护进程,需要通信的进程首先连接到DBus守护进程,在想要发送消息时,其先发送到守护进程,再通过DBus守护进程转到目标进程中.守护进程相当于消息流通的路由器的角色,是一个高效的消息管道.具体工作模式:
DBus消息主要有四类:
- 方法调用信息MethodCall:此消息将会触发一个函数调用
- 方法调用返回MethodReturn:当函数执行完之后返回执行结果给调用进程
- 错误消息Error Signal:函数执行触发错误时发送此消息
- 通知消息Signal:可以理解为一个事件,不触发函数的调用,但是对此消息感兴趣的进程可以监听此消息并进行处理.
DBus通信模式可以降低系统开发复杂度和耦合性,提升模块能力的复用性和开发效率.通常对于移动端开发使用C/S模式,客户端与服务通过DBus通信机制,在约定好接口后就可以独立开发,彼此不再依赖和影响.
进程间通信主要有两种接入方式,一种时提供功能服务进程,其需要注册对外开发的方法或信号,一种时以客户端身份接入,访问其他进程提供的功能
二、QtDBus编程
2.1 Qt DBus服务端
2.1.1 注册DBus服务
通过QDBusConnection::registerService(QString serviceName)进行注册DBus服务,主要的要素是服务名称serviceName,此是唯一的.如果服务名在别的进程已经被注册了,则其会返回失败,但是可以在同一个进程中使用同一个服务名称。注册DBus服务目的是为了dbus总线上提供对外访问的入口,这样其他进程才能请求该服务。
2.1.2 注册DBus对象
dbus总线建立连接之后,就需要向DBus总线注册对象,注册对象的目的,是为了暴露一些接口到总线上,这样其他进程就可以连接感兴趣的信号接口,或者调用感兴趣的函数接口。Qt通过调用QDBusConnection::reginterObject(QString servicePath , QObject *, RegisterOptions options) 将指定路径path下的接口注册到对象中去.options限定对象object对外公开的具体接口类型.options可以为QDBusConnection::ExportAllSlots|QDBusConnection::ExportAllSignals|QDBusConnection::ExportAllProperties|QDBusConnection::ExportAllInvokables表示该类中所有的槽函数、信号函数、属性以及Q_INVOKABLE标记的函数都是接口函数,即外部进程可以调用该类的槽函数、Q_INVOKABLE标记的函数;当信号发出时,外界也能接收到发出的信号;外界进程可用通过调用property()和setProperty()方法获取、设置属性值。
2.1.3 函数接口
2.1.3.1 类声明要求
Qt中,DBus服务对外提供接口的对象可以基于QObject或QDBusAbstractAdaptor,因此,声明的类必须继承QObject或者QDBusAbstractAdaptor。
继承于QDBusAbstractAdaptor,其主要作用是适配。在创建子类时需要父类,而在注册对象的时候注册的是其父亲指针,是典型的适配器模型.示例代码如下
class Service: public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface","com.mytest.dbus")
public:
Service(QObject *parent=0);
...
}
代码中的宏Q_CLASS_INFO为类提供额外的信息,而这些信息是通过name和value的呈现的。Q_CLASSINFO(“D-Bus Interface”, “com.mytest.dbus.interface”)表示该类提供DBus接口信息,这样编译器会根据此生成可见的接口.
继承于QObject共性的都需要是Q_CLASSINFO声明自己是dbus接口信息.但QObject注册到服务的都是自己的方法,因此在注册对象时,对象是自己作为dbus的接口对象。
2.1.3.2 信号函数接口创建和发送
信号的创建有两种方式,一种在.h文件中用关键字signals表明函数是信号函数,可以通过emit关键字发送这个函数。代码如下:
声明信号
signals:
void testSignal(int value);
发送信号
emit testSignal(m_value);
还有一种是使用QDBusMessage::createSignal创建一个信号函数,通过send()发送信号。代码如下:
创建信号
QDBusMessage message =QDBusMessage::createSignal(servicePath , serviceInterface , "createSignal");
给信号赋值
message << QString("Hello world!");
发送信号
QDBusConnection::sessionBus().send(message);
2.1.3.3 槽函数函数接口
槽函数需要用关键字slots关键字表明,并且要实现声明的槽函数:
public slots:
int testMethodCall(int value);
实现:
int Service::testMethodCall(int value)
{
qDebug() << "testMethodCall is called";
m_value = value;
emit testSignal(m_value);
qDebug() << "emit testSignal";
return m_value;
}
2.1.3.4 Q_INVOKABLE函数函数接口
此类函数需要用关键字Q_INVOKABLE关键字表明,并且要实现声明的函数:
Q_INVOKABLE int testInvokable();
实现:
int Service::testInvokable()
{
qDebug() << Q_FUNC_INFO << "m_value: " << m_value;
return m_value;
}
使用Q_INVOKABKE修饰成员函数,目的在于被修饰的成员函数能够被元对象系统所唤起。
2.1.3.5 属性
定义属性
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
上述代码含义:
1、定义一个属性value,类型是int类型
2、READ value表示获取属性值时,从value函数读取。因此,value必须定义和实现,并且返回值是int类型
3、WRITE setValue表示设置属性值时,通过setValue函数设置,因此,valsetValueue必须定义和实现,并且函数有一个int类型的参数
4、NOTIFY valueChanged表示属性值发生变化时,发送valueChanged信号,绑定这个属性的变量也会发生变化
声明读、写、信号函数
int getValue();
void setValue(int value);
signals:
void valueChanged();
实现读、写函数,发送信号
// 属性读函数
int Service::getValue()
{
qDebug() << "property read";
return m_value;
}
// 属性写函数
void Service::setValue(int value)
{
m_value = value;
emit valueChanged();
qDebug() << "property write:" << m_value;
}
2.1.4 实例代码
要使用QtDBus模块,需要在工程文件中增加QT += dbus代码用于来链接QtDBus库。下面就介绍一下,在元心系统下,怎么使用QtDBus.
QtDBus主要作用是进程间通信,那么就需要有两个进程,一个作为DBus的Service进程,另一个作为DBus的Client进程。为了方便介绍,可以在元心提供测编译器新建一个支持服务的图形应用程序工程,这样就可以将服务程序作为DBus程序,应用程序作为DBus的Client程序。
新建工程一个支持服务的图形应用程序工程。
首先,先写一个Dbus服务端。service.h如下:
#ifndef SERVICE_H
#define SERVICE_H
#include <QObject>
#include <QDebug>
#include <QDBusAbstractAdaptor>
#include <QDBusContext>
const QString serviceName = "com.mytest.dbus";
const QString servicePath = "/com/mytest/dbus";
const QString serviceInterface = "com.mytest.dbus.interface";
//test class
class TestClass{
public:
TestClass(){
id = "";
name = "";
}
QString id;
QString name;
};
Q_DECLARE_METATYPE(TestClass)
class Service : public QObject, public QDBusContext
{
Q_OBJECT
//定义Interface名称为com.mytest.dbus.interface
Q_CLASSINFO("D-Bus Interface", "com.mytest.dbus.interface")
Q_PROPERTY(int value READ getValue WRITE setValue NOTIFY valueChanged)
public:
explicit Service(QObject *parent = NULL);
~Service();
Q_INVOKABLE int testInvokable();
void init();
int getValue();
void setValue(int value);
signals:
void valueChanged();
signals:
void testSignal(int value);
public slots:
int testMethodCall(int value);
TestClass testMethodCallWithTestClass(const TestClass &testClass);
QString testAsyncCall(QString value);
int testCreateMethodCall(int value);
private:
int m_value;
};
#endif // SERVICE_H
Dbus服务端service.cpp如下:
#include "service.h"
#include <QDBusConnection>
#include <QDBusError>
#include <QDBusMessage>
#include <QDBusMetaType>
#include <QThread>
#include <QDBusConnectionInterface>
#include <QDBusContext>
Service::Service(QObject *parent) : QObject(parent)
{
// 注册成元对象类型,以便信号槽可以传递自定义类型参数
qRegisterMetaType<TestClass>("TestClass");
// 把自定义类型注册dbus类型
qDBusRegisterMetaType<TestClass>();
m_value = 0;
init();
}
Service::~Service()
{
}
int Service::testInvokable()
{
qDebug() << Q_FUNC_INFO << "==========m_value: " << m_value;
return m_value;
}
void Service::init()
{
m_value = 1000;
//建立到session bus的连接
QDBusConnection connection = QDBusConnection::sessionBus();
qDebug()<<"========register object";
//注册对象,并把定义的槽函数、信号函数、属性、Q_INVOKABLE标记的函数导出,即外部进程可以调用这个导出的函数或属性
connection.registerObject(servicePath, this,QDBusConnection::ExportAllSlots
|QDBusConnection::ExportAllSignals
|QDBusConnection::ExportAllProperties
|QDBusConnection::ExportAllInvokables);
//在session bus上注册服务
qDebug()<<"======register service";
if(!connection.registerService(serviceName))
{
qDebug() << "========error:" << connection.lastError().message();
}
}
// 属性读函数
int Service::getValue()
{
qDebug() << "=======property read";
return m_value;
}
// 属性写函数
void Service::setValue(int value)
{
m_value = value;
emit valueChanged();
qDebug() << "========property write:" << m_value;
}
int Service::testMethodCall(int value)
{
// 创建一个messsgeSignal信号,并发送
QDBusMessage message =QDBusMessage::createSignal(servicePath , serviceInterface , "messsgeSignal");
message << QString("Hello world!");
QDBusConnection::sessionBus().send(message);
qDebug() << "==========send message signal";
// 发送信号
emit testSignal(value);
// 返回外部进程传入的值
m_value = value;
return m_value;
}
// 测试自定义类型
TestClass Service::testMethodCallWithTestClass(const TestClass &testClass)
{
qDebug() << Q_FUNC_INFO << testClass.id << testClass.name << endl;
return testClass;
}
// 测试异步调用
QString Service::testAsyncCall(QString value)
{
qDebug() << Q_FUNC_INFO << "========begin" << value << endl;
QThread::sleep(5);
qDebug() << Q_FUNC_INFO << "========end" << value << endl;
return value;
}
int Service::testCreateMethodCall(int value)
{
return value;
}
// 序列化和反序列化自定义类型,以便自定义类型可以在dbus总线上传递
QDBusArgument &operator <<(QDBusArgument &dbusArg, const TestClass &testClass){
dbusArg.beginStructure();
dbusArg << testClass.id << testClass.name;
dbusArg.endStructure();
return dbusArg;
}
const QDBusArgument &operator >>(const QDBusArgument &dbusArg, TestClass &testClass){
dbusArg.beginStructure();
dbusArg >> testClass.id >> testClass.name;
dbusArg.endStructure();
return dbusArg;
}
使用d-feet查看
2.2 Qt DBus客户端
2.2.1 监测服务注册
Qt中可以使用QDBusServerWatcher监听某个service是注册或者取消注册,通过关注服务的状态变化信号,完成客户端的一些处理.具体代码如下:
serviceWatcher->setConnection(QDBusConnection::sessionBus());
– 具有监听DBus服务的能力
serviceWatcher->addWatchedService(serviceName);
– 指明监听的服务,可以监控多个服务
serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForRegistration | QDBusServiceWatcher::WatchForUnregistration);
– 指明监听的模式,上述代码指明监听服务的注册和解注册行为
connect(serviceWatcher, &QDBusServiceWatcher::serviceRegistered, this, &Client::handleRegisterResult);
connect(serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &Client::handleUnregisterResult);
– 当服务注册和解注册时,会触发serviceRegistered和serviceUnregistered信号,上述代码连接这两个信号,服务的状态变化信号,做相应的处理。
注意:如果DBus客户端在DBus服务后启动,则有可能监听不到服务注册信号。
2.2.2 绑定DBus服务信号
通过 QDBusConnection::sessionBus().connect(const QString &service, const QString &path, const QString &interface,const QString &name, QObject *receiver, const char *slot)绑定DBus服务导出的信号,其中service时服务名称,path时服务的路径名称,interface是服务的接口名称,name是信号函数名称,receiver是接收信号函数的对象指针,slot是槽函数。代码如下:
bool ret = QDBusConnection::sessionBus().connect(serviceName,
servicePath,
serviceInterface,
"testSignal" ,
this,
SLOT(receiveSignal(int)));
如果绑定信号成功,ret值为true,如果绑定失败,ret值为false。当服务端发送testSignal信号时,槽函数receiveSignal就会接收信号,函数中可以做逻辑处理。
2.2.3 同步接口调用
同步调用DBus服务接口有两用方式可以实现。一种是使用QDBusMessage的createMethodCall函数。代码如下:
- 创建一个QDBusMessage的方法调用
QDBusMessage msg = QDBusMessage::createMethodCall(serviceName ,
servicePath ,
serviceInterface ,
"testMethodCall");
- 给mes传递参数
msg << 100
- 调用方法
QDBusMessage response = QDBusConnection::sessionBus().call(msg);
返回值处理
if (response.type() == QDBusMessage::ReplyMessage)
{
qDebug() << response.arguments().takeFirst().toString();
}
如果返回值类型不是QDBusMessage::ReplyMessage,则说明调用失败。response.arguments()返回的是QList类型。
另外一种调用DBus服务接口的方式是使用QDBusInterface类。代码如下:
- 创建接口对象
interface = new QDBusInterface(serviceName, servicePath, serviceInterface, QDBusConnection::sessionBus());
- 监测接口对象是否可用
bool Client::isVaild()
{
return interface->isValid();
}
若可用,则返回true,或者返回false
3) 接口调用
QDBusReply<int> reply = interface->call("testMethodCall",100)
其中testMethodCall是DBus服务的函数名,100是传入函数的参数值。
返回值处理
if (reply.isValid())
{
qDebug() << Q_FUNC_INFO << reply.value();
return ;
} else {
qDebug() << Q_FUNC_INFO << QString("Call failed");
}
reply.isValid()为false时,则表明调用失败。
2.2.4 异步接口调用
异步接口调用,需要QDBusPendingReply、QDBusPendingCallWatcher 和QDBusInterface配合使用完成。代码如下:
QDBusPendingReply<QString> pCall = interface->asyncCall("testAsyncCall","test async call");
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pCall,this);
QObject::connect(watcher,SIGNAL(finished(QDBusPendingCallWatcher*)),this,SLOT(handleAsyncCallSlot(QDBusPendingCallWatcher*)));
pCall :接收异步调用的返回值
Watcher:监听异步调用函数是否已返回
handleAsyncCallSlot:是槽函数,处理异步调用结果
异步调用的好处是避免被调函数运行时间过长导致客户端挂起当前线程。
2.2.4 属性调用
设置dbus服务的属性值
void Client::setPropertyValue()
{
qDebug() << Q_FUNC_INFO << "set property value 10000000"<< endl;
interface->setProperty("value", 10000000);
}
获取dbus服务的属性值
void Client::getPropertyValue()
{
qDebug() << Q_FUNC_INFO << "get property value: " << interface->property("value").toInt()<< endl;
}
2.2.5 客户端代码
下面再写一个DBus客户端,client.h如下:
#ifndef CLIENT_H
#define CLIENT_H
#include <QObject>
#include <QDBusInterface>
#include <QDebug>
#include <QDBusPendingCallWatcher>
#include <QDateTime>
#include <QDBusServiceWatcher>
#include <QDBusContext>
const QString serviceName = "com.mytest.dbus";
const QString servicePath = "/com/mytest/dbus";
const QString serviceInterface = "com.mytest.dbus.interface";
class TestClass{
public:
TestClass(){
id = "";
name = "";
}
QString id;
QString name;
};
Q_DECLARE_METATYPE(TestClass)
class Client : public QObject, public QDBusContext{
Q_OBJECT
public:
explicit Client(QObject* parent =NULL);
~Client();
Q_INVOKABLE void beginDBusTest();
public slots:
void receiveSignal(int value);
void receiveMessageSignal(QString value);
void handleAsyncCallSlot(QDBusPendingCallWatcher* watch);
private slots:
void handleRegisterResult(const QString &serviceName);
void handleUnregisterResult(const QString &serviceName);
private:
void init();
void callDBusMethod();
void callDBusMethodWithCustomStruct();
void callDBusMethodByMessage();
void asyCallDBusMethod();
void setPropertyValue();
void getPropertyValue();
bool isVaild();
void callDBusInvokableMethod();
private:
QDBusInterface *interface;
QDBusServiceWatcher *serviceWatcher;
};
#endif // CLIENT_H
DBus客户端,client.cpp如下:
#include "client.h"
#include <QDBusConnection>
#include <QDBusArgument>
#include <QDBusMetaType>
#include <QDBusReply>
#include <QDBusConnectionInterface>
Client::Client(QObject *parent):QObject(parent),
serviceWatcher(new QDBusServiceWatcher())
{
// 监控dbus的注册信号和解注册信号
serviceWatcher->setConnection(QDBusConnection::sessionBus());
serviceWatcher->addWatchedService(serviceName);
serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForRegistration | QDBusServiceWatcher::WatchForUnregistration);
connect(serviceWatcher, &QDBusServiceWatcher::serviceRegistered, this, &Client::handleRegisterResult);
connect(serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &Client::handleUnregisterResult);
// 注册成元对象类型,以便信号槽可以传递自定义类型参数
qRegisterMetaType<TestClass>("testClass");
// 把自定义类型注册dbus类型
qDBusRegisterMetaType<TestClass>();
init();
}
Client::~Client()
{
if(interface != NULL){
delete interface;
interface = NULL;
}
}
void Client::beginDBusTest()
{
if(!isVaild()){
qDebug() << Q_FUNC_INFO << "dbus is not vaild"<< endl;
return;
}
qDebug() << Q_FUNC_INFO << "======dbus is vaild======="<< endl;
callDBusMethod();
callDBusMethodWithCustomStruct();
callDBusMethodByMessage();
asyCallDBusMethod();
getPropertyValue();
setPropertyValue();
getPropertyValue();
callDBusInvokableMethod();
}
// dbus服务信号发出处理函数
void Client::receiveSignal(int value)
{
qDebug() << "=======receive signal value: ========" << value<< endl;
}
// dbus服务信号发出处理函数
void Client::receiveMessageSignal(QString value)
{
qDebug() << Q_FUNC_INFO << "========value: =========" << value<< endl;
}
// 异步调用处理函数
void Client::handleAsyncCallSlot(QDBusPendingCallWatcher *watch)
{
qDebug()<<"=========DbusTest::handleAsyncCallSlot======"<<watch->reply().arguments() << "time: " << QDateTime::currentDateTime().toString("hh:mm:ss") << endl;
}
// dbus服务注册处理函数
void Client::handleRegisterResult(const QString &serviceName)
{
qDebug() << Q_FUNC_INFO << "======serviceName: ======" << serviceName << endl;
}
// dbus服务解注册处理函数
void Client::handleUnregisterResult(const QString &serviceName)
{
qDebug() << Q_FUNC_INFO << "=========serviceName: ====" << serviceName << endl;
}
void Client::init()
{
// 关联dbus信号
bool ret = QDBusConnection::sessionBus().connect(serviceName,
servicePath,
serviceInterface,
"testSignal" ,
this,
SLOT(receiveSignal(int)));
if(!ret) {
qDebug()<<"=======testSignal connect failed" << endl;
}
// 关联dbus信号
ret = QDBusConnection::sessionBus().connect(serviceName,
servicePath,
serviceInterface,
"messsgeSignal" ,
this,
SLOT(receiveMessageSignal(QString)));
if(!ret) {
qDebug()<<"=======messsgeSignal connect failed" << endl;
}
// 创建QDBusInterface接口对象
interface = new QDBusInterface(serviceName, servicePath,
serviceInterface, QDBusConnection::sessionBus());
// 判断接口对象是否可用
if (!interface->isValid())
{
qDebug() << QDBusConnection::sessionBus().lastError().message();
}
}
// 同步调用dbus服务提供的接口函数
void Client::callDBusMethod()
{
QDBusReply<int> reply = interface->call("testMethodCall",100);
if (reply.isValid())
{
qDebug() << Q_FUNC_INFO << reply.value() << endl;
return ;
} else {
qDebug() << Q_FUNC_INFO << QString("=======Call failed") << endl;
}
}
// 测试自定义类型
void Client::callDBusMethodWithCustomStruct()
{
TestClass testClass;
testClass.id = "1";
testClass.name = "testCustomStruct";
QDBusReply<TestClass> reply = interface->call("testMethodCallWithTestClass",QVariant::fromValue<TestClass>(testClass));
qDebug() << Q_FUNC_INFO << "======id: " <<reply.value().id << "name:" << reply.value().name << endl;
}
// 创建一个dbus的函数调
void Client::callDBusMethodByMessage()
{
qDebug() << Q_FUNC_INFO << "begin";
QDBusMessage msg = QDBusMessage::createMethodCall(serviceName ,
servicePath ,
serviceInterface ,
"testCreateMethodCall");
msg << 1000;
QDBusMessage response = QDBusConnection::sessionBus().call(msg);
if (response.type() == QDBusMessage::ReplyMessage)
{
qDebug() << Q_FUNC_INFO << "value: " << response.arguments().takeFirst().toInt() << endl;
}
qDebug() << Q_FUNC_INFO << "end";
}
// 异步调用dbus服务提供的接口函数
void Client::asyCallDBusMethod()
{
qDebug() << Q_FUNC_INFO << "begin time: " << QDateTime::currentDateTime().toString("hh:mm:ss") << endl;
QDBusPendingReply<QString> pCall = interface->asyncCall("testAsyncCall","test async call");
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pCall,this);
QObject::connect(watcher,SIGNAL(finished(QDBusPendingCallWatcher*)),this,SLOT(handleAsyncCallSlot(QDBusPendingCallWatcher*)));
}
// 设置dbus服务的属性值
void Client::setPropertyValue()
{
qDebug() << Q_FUNC_INFO << "set property value 10000000"<< endl;
interface->setProperty("value", 10000000);
}
// 获取dbus服务的属性值
void Client::getPropertyValue()
{
qDebug() << Q_FUNC_INFO << "get property value: " << interface->property("value").toInt()<< endl;
}
// 判定dbus接口对象代理是否可用
bool Client::isVaild()
{
return interface->isValid();
}
void Client::callDBusInvokableMethod()
{
qDebug() << Q_FUNC_INFO << "call invokable method: " <<interface->call("testInvokable").arguments().at(0).toInt();
}
// 序列化和反序列化自定义类型,以便自定义类型可以在dbus总线上传递
QDBusArgument &operator <<(QDBusArgument &dbusArg, const TestClass &testClass){
dbusArg.beginStructure();
dbusArg << testClass.id << testClass.name;
dbusArg.endStructure();
return dbusArg;
}
const QDBusArgument &operator >>(const QDBusArgument &dbusArg,TestClass &testClass){
dbusArg.beginStructure();
dbusArg >> testClass.id >> testClass.name;
dbusArg.endStructure();
return dbusArg;
}
2.3、新定义类型DBus传递:
2.3.1首先自定义新类型类
可以继承QObject,也可以不继承QObject
class TestClass{
public:
TestClass(){
id = "";
name = "";
}
QString id;
QString name;
};
Q_DECLARE_METATYPE(TestClass)
2.3.2要将此类声明为metatype和dbus可传输的类型
首先必须使用Q_DECLARE_METATYPE宏处理,这保证了此类在Qt的元系统可见,并且其可以被QVariant直接转换。如下:
MyStruct s;
QVariant var;
var.setValue(s); // copy s into the variant
MyStruct s2 = var.value<MyStruct>();
其次使用int qRegisterMetaType(const char * typeName)注册。则其可以使用QObject的property属性,信号槽可用,如:
qRegisterMetaType(“MyClass”);
最后将对象注册为DBUS总线上可以传输的数据类型,即:
qDBusRegisterMetaType(); 注册了此,必须同时实现 操作符函数 >> & <<,进行序列化,且序列化字段顺序必须一致,序列化的目的是:DBUS文本消息和CustomStruct 可以双向转换
如:
// 序列化和反序列化自定义类型,以便自定义类型可以在dbus总线上传递
QDBusArgument &operator <<(QDBusArgument &dbusArg, const TestClass &testClass){
dbusArg.beginStructure();
dbusArg << testClass.id << testClass.name;
dbusArg.endStructure();
return dbusArg;
}
const QDBusArgument &operator >>(const QDBusArgument &dbusArg,TestClass &testClass){
dbusArg.beginStructure();
dbusArg >> testClass.id >> testClass.name;
dbusArg.endStructure();
return dbusArg;
}
以上两步,是DBus客户端和服务端都是必须的,且自定义类型必须一致。
2.3.3新定义类型测试
客户端调用函数如下
// 测试自定义类型
void Client::callDBusMethodWithCustomStruct()
{
TestClass testClass;
testClass.id = "1";
testClass.name = "testCustomStruct";
QDBusReply<TestClass> reply = interface->call("testMethodCallWithTestClass",QVariant::fromValue<TestClass>(testClass));
qDebug() << Q_FUNC_INFO << "======id: " <<reply.value().id << "name:" << reply.value().name << endl;
}
服务端提供的被调用函数如下:
// 测试自定义类型
TestClass Service::testMethodCallWithTestClass(const TestClass &testClass)
{
qDebug() << Q_FUNC_INFO << testClass.id << testClass.name << endl;
return testClass;
}
2.4 命令行使用DBus
dbus 发送信号
dbus-send --session --type=signal --print-reply --dest=com.syberos.zzwdbusserver /com/syberos/zzwdbusserver com.syberos.zzwdbusserver.Interface.textPropertyChanged
dbus 调用函数
dbus-send --session --type=method_call --print-reply --dest=com.syberos.zzwdbusserver "/com/syberos/zzwdbusserver" com.syberos.zzwdbusserver.Interface.textPropertyChanged
dbus 查看信号和方法注册详情
dbus-send --session --print-reply --dest=com.syberos.zzwdbusserver /com/syberos/zzwdbusserver org.freedesktop.DBus.Introspectable.Introspect
查看名称
dbus-send --session --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListActivatableNames
查看所有dbus的信息
dbus-send --session --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames
字段说明
Session:会话dbus
Dest:dbus服务名
Type:操作类型 method_call:表示调用接口 signal表示发送信号
print-reply :打印返回结果
/com/syberos/zzwdbusserver :dbus路径名称
com.syberos.zzwdbusserver.Interface:dbus接口名称
noReply:函数名称
三、demo说明
如上图,Demo中包含三个部分,界面、DBus Client 和DBus Service。
界面: 包含一个Button,用于触发Dbus调用,即客户端低调用服务端接口。触发函数为client.cpp中beginDBusTest函数。
DBus client:dbus客户端逻辑代码,主要内容包含client.h和client.cpp两个文件。功能包含:监控dbus服务的注册和解注册信号、绑定dbus服务端提供的信号函数接口、调用dbus服务的槽函数接口和Q_INVOKABLE标记的函数接口、设置和获取属性值。
DBus Service:注册dbus服务、注册dbus对象、暴露信号函数接口、槽函数接口、Q_INVOKABLE标记的函数接口以及属性。
四、GDBus编程
4.1 Glib-dbus简介
Dbus-glib是GNU标准库,在Dbus接口上封装,方便上层服务与应用更好的使用。其形如一个Dbus代理服务器,由它进行所有Dbus消息的遍历与转发,服务端与消息发送端只需要向dbus deamon申请注册唯一的dbus name 、绑定GOBJECT后,dbus deamon就会将申请连到到该dbus name的Dbus信息转发给指定应用。dbus daemon不对消息重新排序,如果发送了两条消息到同一个进程,它们将按照发送顺序接受到。接受进程并需要按照顺序发出应答消息,例如在多线程中处理这些消息,应答消息的发出是没有顺序的。消息都有一个序列号可以与应答消息进行配对。
4.1 GDBus服务端
4.1.1 xml的编写及绑定文件的生成
在GLib中,通过dbus表现出GObject,必须写XML文件描述这个对象的方法等属性。通过XML文件和dbus-binding-tool工具,可以很方便的自动创建出易于使用的dbus代理对象。例如下面的myglibdbus.xml文件描述了三个函数和一个信号,其中函数work有一个输入参数msg(char)和一个输出参数ret(gint),函数receive有一个输入参数msg(char)和一个输出参数ret(char*),函数exit有一个输出参数ret(gint),信号info_alert传递一个参数类型为字符串的变量。一个node可以有多个interface ,一个interface可以有多个method(函数)或signal(信号)。 myglibdbus.xml的具体内容如下:
<?xml version="1.0" encoding="UTF-8" ?>
<node name="/org/freedesktop/myglibdbus">
<interface name="org.freedesktop.myglibdbus">
<method name="work">
<annotation name="org.freedesktop.DBus.GLib.Async" value="" />
<arg type="s" name="msg" direction="in"/>
<arg type="i" name="ret" direction="out" />
</method>
<method name="receive">
<annotation name="org.freedesktop.DBus.GLib.Async" value="" />
<arg type="s" name="msg" direction="in"/>
<arg type="s" name="ret" direction="out" />
</method>
<method name="exit">
<annotation name="org.freedesktop.DBus.GLib.Async" value="" />
<arg type="i" name="ret" direction="out" />
</method>
<signal name="info_alert">
<arg type="s" name="value" direction="out" />
</signal>
</interface>
</node>
在进行编写代码之前首先要确保安装了dbus的开发包,安装命令如下:
sudo apt install libglib2.0-dev libdbus-glib-1-dev libdbus-1-dev
通过dbus-binding-tool生成绑定文件,如下:
dbus-binding-tool --mode=glib-server --prefix=myglibdbus org.freedesktop.myglibdbus.xml --output=myglibdbus-glue.h
执行上面的命令,则生成了绑定文件myglibdbus-glue.h,该文件无需修改,直接在本地代码中include使用即可。”–prefix”参数定义了对象前缀。设对象前缀是KaTeX parse error: Expected group after '_' at position 45: …构变量名就是dbus_glib_̲(prefix) _object_info,如:dbus_glib_myglibdbus_object_info。
绑定文件会为接口方法定义回调函数。回调函数的名称是这样的:首先将xml中的方法名称转换到全部小写,下划线分隔的格式,然后增加前缀
(
p
r
e
f
i
x
)
。
例
如
x
m
l
中
的
函
数
w
o
r
k
,
绑
定
文
件
就
会
引
用
一
个
名
称
为
(prefix)_。例如xml中的函数work,绑定文件就会引用一个名称为
(prefix)。例如xml中的函数work,绑定文件就会引用一个名称为(prefix)_work的函数,即:myglibdbus_work。
myglibdbus-glue.h代码如下:
/* Generated by dbus-binding-tool; do not edit! */
/* This file is generated by glib-genmarshal, do not modify it. This code is licensed under the same license as the containing project. Note that it links to GLib, so must comply with the LGPL linking clauses. */
#include <glib-object.h>
#ifdef G_ENABLE_DEBUG
#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
#define g_marshal_value_peek_char(v) g_value_get_schar (v)
#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
#define g_marshal_value_peek_int(v) g_value_get_int (v)
#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
#define g_marshal_value_peek_long(v) g_value_get_long (v)
#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
#define g_marshal_value_peek_float(v) g_value_get_float (v)
#define g_marshal_value_peek_double(v) g_value_get_double (v)
#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
#define g_marshal_value_peek_param(v) g_value_get_param (v)
#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
#define g_marshal_value_peek_object(v) g_value_get_object (v)
#define g_marshal_value_peek_variant(v) g_value_get_variant (v)
#else /* !G_ENABLE_DEBUG */
/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
* Do not access GValues directly in your code. Instead, use the
* g_value_get_*() functions
*/
#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
#define g_marshal_value_peek_char(v) (v)->data[0].v_int
#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
#define g_marshal_value_peek_int(v) (v)->data[0].v_int
#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
#define g_marshal_value_peek_long(v) (v)->data[0].v_long
#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
#define g_marshal_value_peek_float(v) (v)->data[0].v_float
#define g_marshal_value_peek_double(v) (v)->data[0].v_double
#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer
#endif /* !G_ENABLE_DEBUG */
#define dbus_glib_marshal_myglibdbus_VOID__POINTER g_cclosure_marshal_VOID__POINTER
#define dbus_glib_marshal_myglibdbus_NONE__POINTER dbus_glib_marshal_myglibdbus_VOID__POINTER
/* Prototype for -Wmissing-prototypes */
G_BEGIN_DECLS
extern
void dbus_glib_marshal_myglibdbus_VOID__STRING_POINTER (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data);
G_END_DECLS
void
dbus_glib_marshal_myglibdbus_VOID__STRING_POINTER (GClosure *closure,
GValue *return_value G_GNUC_UNUSED,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint G_GNUC_UNUSED,
gpointer marshal_data)
{
typedef void (*GMarshalFunc_VOID__STRING_POINTER) (gpointer data1,
gpointer arg1,
gpointer arg2,
gpointer data2);
GCClosure *cc = (GCClosure *) closure;
gpointer data1, data2;
GMarshalFunc_VOID__STRING_POINTER callback;
g_return_if_fail (n_param_values == 3);
if (G_CCLOSURE_SWAP_DATA (closure))
{
data1 = closure->data;
data2 = g_value_peek_pointer (param_values + 0);
}
else
{
data1 = g_value_peek_pointer (param_values + 0);
data2 = closure->data;
}
callback = (GMarshalFunc_VOID__STRING_POINTER) (marshal_data ? marshal_data : cc->callback);
callback (data1,
g_marshal_value_peek_string (param_values + 1),
g_marshal_value_peek_pointer (param_values + 2),
data2);
}
#define dbus_glib_marshal_myglibdbus_NONE__STRING_POINTER dbus_glib_marshal_myglibdbus_VOID__STRING_POINTER
#include <dbus/dbus-glib.h>
static const DBusGMethodInfo dbus_glib_myglibdbus_methods[] = {
{ (GCallback) myglibdbus_work, dbus_glib_marshal_myglibdbus_NONE__STRING_POINTER, 0 },
{ (GCallback) myglibdbus_receive, dbus_glib_marshal_myglibdbus_NONE__STRING_POINTER, 55 },
{ (GCallback) myglibdbus_exit, dbus_glib_marshal_myglibdbus_NONE__POINTER, 113 },
};
const DBusGObjectInfo dbus_glib_myglibdbus_object_info = { 1,
dbus_glib_myglibdbus_methods,
3,
"org.freedesktop.myglibdbus\0work\0A\0msg\0I\0s\0ret\0O\0F\0N\0i\0\0org.freedesktop.myglibdbus\0receive\0A\0msg\0I\0s\0ret\0O\0F\0N\0s\0\0org.freedesktop.myglibdbus\0exit\0A\0ret\0O\0F\0N\0i\0\0\0",
"org.freedesktop.myglibdbus\0info_alert\0\0",
"\0"
};
4.1.2 创建MyGlibDbus对象
dbus-glib定义向dbus daemon申请一个注册信息的形式为GObject(C语言)的对象。dbus-glib需要用GObject实现dbus对象,故需要实现一个对象,继承于GObject。
先新建文件myglidbus.h和myglibdbus.c(可根据个人需求创建不同的文件),在头文件myglidbus.h中定义对象,如下所示:
struct _MyGlibDbus {
GObject parent;
};
struct _MyGlibDbusClass {
GObjectClass parent_class;
};
typedef struct _MyGlibDbus MyGlibDbus;
typedef struct _MyGlibDbusClass MyGlibDbusClass;
在GObject中,类是两个结构体的组合,一个是实例结构体,另一个是类结构体,MyGlibDbus是实例结构体,MyGlibDbusClass是类结构体。
在myglibdbus.c文件中加入 G_DEFINE_TYPE(MyGlibDbus, myglibdbus, G_TYPE_OBJECT);
G_DEFINE_TYPE可以让GObject库的数据类型系统能够识别我们所定义的MyGlibDbus类类型,它接受三个参数,第一个参数是类名,即MyGlibDbus;第二个参数则是类的成员函数(面向对象术语称之为“方法”或“行为”)名称的前缀,例如myglibdbus_get_type函数即为MyGlibDbus类的一个成员函数,“myglibdbus”
声明类的函数
//向GObject库所提供的类型管理系统提供要注册的MyGlibDbus类类型的相关信息,可以不实现,但必须要声明
GType myglibdbus_get_type(void);
#define MYGLIBDBUS_TYPE_OBJECET (myglibdbus_get_type())
//声明类的函数(类成员的构造函数)
void myglibdbus_init(MyGlibDbus *dbus)
{
}
//声明类的函数(类结构的构造函数,与类成员构造函数区别在于,该构造函数只在该类定义时运行一次,
//常用来进行消息信号的初始化等。而myglibdbus_init则在创建成员时都会调用一次(如obj = g_object_new))
void myglibdbus_class_init(MyGlibDbusClass * kclass)
{
}
4.1.3 向dbus deamon申请注册
- 建立与D-Bus后台的连接
DBusGConnection connection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
2.申请一个会话总线 DBUS_SERVICE_DBUS: org.freedesktop.DBus DBUS_PATH_DBUS: /org/freedesktop/DBus DBUS_INTERFACE_DBUS:org.freedesktop.DBus
dbus_proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS,
DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
3.调用dbusdaemon的函数“RequestName”,申请一个DBUS名为org.freedesktop.myglibdbus的注册信息
ret = dbus_g_proxy_call(dbus_proxy, “RequestName”, &error,
G_TYPE_STRING, MYGLIBDBUS_NAME,
G_TYPE_UINT,
DBUS_NAME_FLAG_DO_NOT_QUEUE,
G_TYPE_INVALID,
G_TYPE_UINT, &request_name_result,
G_TYPE_INVALID);
4.创建一个MyGlibDbus,MYGLIBDBUS_TYPE_OBJECET是之前提到的向GObject库所提供的类型管理系统提供要注册的MyGlibDbus类类型的相关信息
(MyGlibDbus) g_object_new(MYGLIBDBUS_TYPE_OBJECET, NULL);
5.向dbus-glib登记对象信息,安装关于给定对象GType的自省信息,以便允许通过名称调用对象上的方法。这样,可以在收到信息的时候,可以触发调用它的方法。
dbus_g_object_type_install_info(MYGLIBDBUS_TYPE_OBJECET,
&dbus_glib_myglibdbus_object_info);
5.将对象在指定的path注册到连接上。 在给定路径上注册一个GObject。 当有消息通过连接,经过路径,找到对象后,根据前面前面的dbus_g_object_type_insall_info,能够调用对应的处理方式
//申请之前定义的一个对象MyGlibDbus,将该对象与bus绑定
dbus_g_connection_register_g_object(connection, MYGLIBDBUS_PATH, G_OBJECT(dbus));
这样基础dbus服务创建成功了,接着就是dbus方法的实现了。
4.1.4 函数接口
4.1.4.1 method函数的实现
gint myglibdbus_work(MyGlibDbus *dbus, gchar *msg, DBusGMethodInvocation *ret_value, GError **error)
{
gint ret = 0;
g_printf("msg:%s\n", msg);
info_alert_dbus_signal_sendmsg(dbus, "work method");
ret = 24;
dbus_g_method_return(ret_value, ret);
//if error, call g_set_error ???
return 0;
}
gint myglibdbus_receive(MyGlibDbus *dbus, gchar *msg, DBusGMethodInvocation *ret_value, GError **error)
{
gchar *result;
g_printf("msg:%s\n", msg);
info_alert_dbus_signal_sendmsg(dbus, "receive method");
result = g_strdup("hahaha!!!");
dbus_g_method_return(ret_value, result);
g_free(result);
return 0;
}
gint myglibdbus_exit(MyGlibDbus *dbus, DBusGMethodInvocation *ret_value, GError **error)
{
gint ret = 0;
dbus_g_method_return(ret_value, ret);
exit(0);
return ret;
}
4.1.4.2 发送signal
1.在myglibdbus_class_init时,通过g_signal_new生成一个新信号句柄并绑定回调函数
signals[SIG_INFO_ALERT] = g_signal_new("info_alert",
G_OBJECT_CLASS_TYPE(kclass),
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
0,
NULL,
NULL,
g_cclosure_marshal_VOID__STRING,/*the function to translate arrays of parameter values to signal emissions into C language callback invocations. 在/usr/include/glib-2.0/gobject/gmarshal.h中定,如果结构参数复杂需自行定义*/
G_TYPE_NONE,/*返回值,因为信号没有返回,所以为NONE*/
1,/*参数数目*/
G_TYPE_STRING);/*参数类型*/
2.通过g_signal_emit发送信号
gint info_alert_dbus_signal_sendmsg(MyGlibDbus *dbus, gchar *info)
{
g_signal_emit(dbus,
signals[SIG_INFO_ALERT],
0,
info);
return 0;
}
4.2 Glib-dbus客户端
4.2.1 使用dbus-binding-tool方式生成调用dbus服务的方法
dbus-binding-tool --mode=glib-client --prefix=myglibdbus myglibdbus.xml > myglibdbus_proxy.h
myglibdbus_proxy.h代码如下:
/* Generated by dbus-binding-tool; do not edit! */
#include <glib.h>
#include <dbus/dbus-glib.h>
G_BEGIN_DECLS
#ifndef _DBUS_GLIB_ASYNC_DATA_FREE
#define _DBUS_GLIB_ASYNC_DATA_FREE
static inline void
_dbus_glib_async_data_free (gpointer stuff)
{
g_slice_free (DBusGAsyncData, stuff);
}
#endif
#ifndef DBUS_GLIB_CLIENT_WRAPPERS_org_freedesktop_myglibdbus
#define DBUS_GLIB_CLIENT_WRAPPERS_org_freedesktop_myglibdbus
static inline gboolean
org_freedesktop_myglibdbus_work (DBusGProxy *proxy, const char * IN_msg, gint* OUT_ret, GError **error)
{
return dbus_g_proxy_call (proxy, "work", error, G_TYPE_STRING, IN_msg, G_TYPE_INVALID, G_TYPE_INT, OUT_ret, G_TYPE_INVALID);
}
typedef void (*org_freedesktop_myglibdbus_work_reply) (DBusGProxy *proxy, gint OUT_ret, GError *error, gpointer userdata);
static void
org_freedesktop_myglibdbus_work_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
{
DBusGAsyncData *data = (DBusGAsyncData*) user_data;
GError *error = NULL;
gint OUT_ret;
dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INT, &OUT_ret, G_TYPE_INVALID);
(*(org_freedesktop_myglibdbus_work_reply)data->cb) (proxy, OUT_ret, error, data->userdata);
return;
}
static inline DBusGProxyCall*
org_freedesktop_myglibdbus_work_async (DBusGProxy *proxy, const char * IN_msg, org_freedesktop_myglibdbus_work_reply callback, gpointer userdata)
{
DBusGAsyncData *stuff;
stuff = g_slice_new (DBusGAsyncData);
stuff->cb = G_CALLBACK (callback);
stuff->userdata = userdata;
return dbus_g_proxy_begin_call (proxy, "work", org_freedesktop_myglibdbus_work_async_callback, stuff, _dbus_glib_async_data_free, G_TYPE_STRING, IN_msg, G_TYPE_INVALID);
}
static inline gboolean
org_freedesktop_myglibdbus_receive (DBusGProxy *proxy, const char * IN_msg, char ** OUT_ret, GError **error)
{
return dbus_g_proxy_call (proxy, "receive", error, G_TYPE_STRING, IN_msg, G_TYPE_INVALID, G_TYPE_STRING, OUT_ret, G_TYPE_INVALID);
}
typedef void (*org_freedesktop_myglibdbus_receive_reply) (DBusGProxy *proxy, char * OUT_ret, GError *error, gpointer userdata);
static void
org_freedesktop_myglibdbus_receive_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
{
DBusGAsyncData *data = (DBusGAsyncData*) user_data;
GError *error = NULL;
char * OUT_ret;
dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_STRING, &OUT_ret, G_TYPE_INVALID);
(*(org_freedesktop_myglibdbus_receive_reply)data->cb) (proxy, OUT_ret, error, data->userdata);
return;
}
static inline DBusGProxyCall*
org_freedesktop_myglibdbus_receive_async (DBusGProxy *proxy, const char * IN_msg, org_freedesktop_myglibdbus_receive_reply callback, gpointer userdata)
{
DBusGAsyncData *stuff;
stuff = g_slice_new (DBusGAsyncData);
stuff->cb = G_CALLBACK (callback);
stuff->userdata = userdata;
return dbus_g_proxy_begin_call (proxy, "receive", org_freedesktop_myglibdbus_receive_async_callback, stuff, _dbus_glib_async_data_free, G_TYPE_STRING, IN_msg, G_TYPE_INVALID);
}
static inline gboolean
org_freedesktop_myglibdbus_exit (DBusGProxy *proxy, gint* OUT_ret, GError **error)
{
return dbus_g_proxy_call (proxy, "exit", error, G_TYPE_INVALID, G_TYPE_INT, OUT_ret, G_TYPE_INVALID);
}
typedef void (*org_freedesktop_myglibdbus_exit_reply) (DBusGProxy *proxy, gint OUT_ret, GError *error, gpointer userdata);
static void
org_freedesktop_myglibdbus_exit_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
{
DBusGAsyncData *data = (DBusGAsyncData*) user_data;
GError *error = NULL;
gint OUT_ret;
dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INT, &OUT_ret, G_TYPE_INVALID);
(*(org_freedesktop_myglibdbus_exit_reply)data->cb) (proxy, OUT_ret, error, data->userdata);
return;
}
static inline DBusGProxyCall*
org_freedesktop_myglibdbus_exit_async (DBusGProxy *proxy, org_freedesktop_myglibdbus_exit_reply callback, gpointer userdata)
{
DBusGAsyncData *stuff;
stuff = g_slice_new (DBusGAsyncData);
stuff->cb = G_CALLBACK (callback);
stuff->userdata = userdata;
return dbus_g_proxy_begin_call (proxy, "exit", org_freedesktop_myglibdbus_exit_async_callback, stuff, _dbus_glib_async_data_free, G_TYPE_INVALID);
}
#endif /* defined DBUS_GLIB_CLIENT_WRAPPERS_org_freedesktop_myglibdbus */
G_END_DECLS
4.2.2 创建dbus连接
客户端和服务端在开始创建dbus连接流程一样,首先要调用dbus_g_bus_get建立一个会话DBUS,如下:
DBusGConnection *bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
4.2.3 获取一个对象代理
DBusGProxy * remote_object = dbus_g_proxy_new_for_name (bus,
MYGLIBDBUS_NAME,
MYGLIBDBUS_PATH,
MYGLIBDBUS_INTERFACE);
4.2.4 绑定dbus服务信号
(1)增加一个信号,通知对象调用者需要捕获指定的信号。
dbus_g_proxy_add_signal(remote_object, "info_alert", G_TYPE_STRING, G_TYPE_INVALID);
(2)连接信号,将处理函数handler连接到指定的信号上。
dbus_g_proxy_connect_signal(remote_object, "info_alert", G_CALLBACK(handler_info_alert), NULL, NULL);
(3)回调函数实现
//接收dbus服务发送的signal
static void handler_info_alert(DBusGProxy *proxy, const char *msg, gpointer user_data)
{
printf("Received signal and it says: %s\n", msg);
}
4.2.4 同步处理
1.关于work method的实现
static void send_message(DBusGProxy *remote_object)
{
//dbus_g_proxy_call_no_reply (proxy, "work", G_TYPE_STRING, "Hello world!", G_TYPE_INVALID);//调用dbus服务的work函数
GError *err = NULL;
int ret = 0;
if (!dbus_g_proxy_call(remote_object, "work", &err,
G_TYPE_STRING, "Hello world!", G_TYPE_INVALID,
G_TYPE_INT, &ret, G_TYPE_INVALID)) {
if (err != NULL) {
if(err->domain == DBUS_GERROR && err->code == DBUS_GERROR_REMOTE_EXCEPTION)
printf("dbus send exception %s:%s",dbus_g_error_get_name(err), err->message);
else
printf("dbus send Error : %s\n", err->message);
g_clear_error(&err);
}
}
else {
printf("send_message return %d\n", ret);
}
}
2.关于receive method 实现
static void receive_message(DBusGProxy *remote_object)
{
GError *err = NULL;
gchar *reply_str = NULL;
if (!dbus_g_proxy_call(remote_object, "receive", &err,
G_TYPE_STRING, "It's SyberOS!", G_TYPE_INVALID,
G_TYPE_STRING, &reply_str, G_TYPE_INVALID)) {
if (err != NULL) {
if(err->domain == DBUS_GERROR && err->code == DBUS_GERROR_REMOTE_EXCEPTION)
printf("dbus receive exception %s:%s",dbus_g_error_get_name(err), err->message);
else
printf("dbus receive Error : %s\n", err->message);
g_clear_error(&err);
}
}
else {
if (reply_str) {
printf("receive_message return %s\n", reply_str);
g_free(reply_str);
}
}
}
3.关于exit method 实现
static void exit_message(DBusGProxy *remote_object)
{
GError *err = NULL;
gchar *reply_str = NULL;
if (!dbus_g_proxy_call(remote_object, "exit", &err,
G_TYPE_INVALID,G_TYPE_STRING, &reply_str, G_TYPE_INVALID)) {
if (err != NULL) {
if(err->domain == DBUS_GERROR && err->code == DBUS_GERROR_REMOTE_EXCEPTION)
printf("dbus receive exception %s:%s",dbus_g_error_get_name(err), err->message);
else
printf("dbus receive Error : %s\n", err->message);
g_clear_error(&err);
}
}
else {
if (reply_str) {
printf("receive_message return %s\n", reply_str);
g_free(reply_str);
}
}
}
4.2.5 异步处理
1.关于work method的实现
static void
org_freedesktop_myglibdbus_work_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
{
DBusGAsyncData *data = (DBusGAsyncData*) user_data;
GError *error = NULL;
gint OUT_ret;
dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INT, &OUT_ret, G_TYPE_INVALID);
(*(org_freedesktop_myglibdbus_work_reply)data->cb) (proxy, OUT_ret, error, data->userdata);
return;
}
static inline DBusGProxyCall*
org_freedesktop_myglibdbus_work_async (DBusGProxy *proxy, const char * IN_msg, org_freedesktop_myglibdbus_work_reply callback, gpointer userdata)
{
DBusGAsyncData *stuff;
stuff = g_slice_new (DBusGAsyncData);
stuff->cb = G_CALLBACK (callback);
stuff->userdata = userdata;
return dbus_g_proxy_begin_call (proxy, "work", org_freedesktop_myglibdbus_work_async_callback, stuff, _dbus_glib_async_data_free, G_TYPE_STRING, IN_msg, G_TYPE_INVALID);
}
2.关于receive method的实现
static void
org_freedesktop_myglibdbus_receive_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
{
DBusGAsyncData *data = (DBusGAsyncData*) user_data;
GError *error = NULL;
char * OUT_ret;
dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_STRING, &OUT_ret, G_TYPE_INVALID);
(*(org_freedesktop_myglibdbus_receive_reply)data->cb) (proxy, OUT_ret, error, data->userdata);
return;
}
static inline DBusGProxyCall*
org_freedesktop_myglibdbus_receive_async (DBusGProxy *proxy, const char * IN_msg, org_freedesktop_myglibdbus_receive_reply callback, gpointer userdata)
{
DBusGAsyncData *stuff;
stuff = g_slice_new (DBusGAsyncData);
stuff->cb = G_CALLBACK (callback);
stuff->userdata = userdata;
return dbus_g_proxy_begin_call (proxy, "receive", org_freedesktop_myglibdbus_receive_async_callback, stuff, _dbus_glib_async_data_free, G_TYPE_STRING, IN_msg, G_TYPE_INVALID);
}
3.关于exit method的实现
static void
org_freedesktop_myglibdbus_exit_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
{
DBusGAsyncData *data = (DBusGAsyncData*) user_data;
GError *error = NULL;
gint OUT_ret;
dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INT, &OUT_ret, G_TYPE_INVALID);
(*(org_freedesktop_myglibdbus_exit_reply)data->cb) (proxy, OUT_ret, error, data->userdata);
return;
}
static inline DBusGProxyCall*
org_freedesktop_myglibdbus_exit_async (DBusGProxy *proxy, org_freedesktop_myglibdbus_exit_reply callback, gpointer userdata)
{
DBusGAsyncData *stuff;
stuff = g_slice_new (DBusGAsyncData);
stuff->cb = G_CALLBACK (callback);
stuff->userdata = userdata;
return dbus_g_proxy_begin_call (proxy, "exit", org_freedesktop_myglibdbus_exit_async_callback, stuff, _dbus_glib_async_data_free, G_TYPE_INVALID);
}
源码
https://download.csdn.net/download/weixin_45492457/62465160