因为以后工作用的到D-bus,这两天抽空看了下c++下得d-bus的使用方法。因为网上对c++下得d-bus使用说明几乎没有,所以,在这里记录下以供同仁使用。同时感谢shengpeng得demo。
这篇文章主要还是对libdbus-c++.so得api调用,其实如果之前有过android下得开发经验,使用过binder得话,对d-bus得工作原理和上手速度会有很大帮助。
不多废话,下面进入正题:
d-bus得整个架构可以在官方说明文档中看到,如果之前有了解过binder的话,理解起来就会比较轻松。如下:
如同binder一样,linux下得IPC需要通过kernel空间得d-bus驱动来进行通信,所以,在进行d-bus通信之前,需要先对安装d-bus得库支持,这里不再详细说明。可以使用系统自带的工具进行安装,例如apt-get install dbus种种。
d-bus分为adaptor端和proxy端(和binder是不是很像?),需要在adaptor端和proxy端都创建了各自的实例后,才能进行通信。
例如,我在proxy端得进程中创建了一个XXproxy得实例,我就能通过这个实例去调用adaptor端对应实例得相应函数,类似于:XXproxy.getversion()(getversion()是在adaptor端的adaptor类型得方法),如果adaptor端得实例想调用proxy端实例得函数,需要将这个希望调用得函数在XML文件声明为signal类型。
上面有说道XML文件,很多人都会疑惑这个XML在d-bus中算作什么角色,其实它相当于一个输入文件,使用d-bus得工具,可以使这个XML自动生成两个类,分别为proxy端和adaptor端的类,程序员再通过继承这两个类,实现这两个类中得纯虚函数,就是完成了proxy端和adaptor端得类的实现。
下面贴出,我这里使用得XML文件,test.xml
<?xml version="1.0" encoding="UTF-8" ?>
<node name="/com/test">
<interface name="com.test.interfacetest">
<method name="getversion">
<arg type="s" name="version" direction="out"/>
</method>
<signal name="display"/>
</interface>
</node>
由上面看到,我们定义了一个node,这个node得name表示得是一个地址,这个地址得意义相当于是一个唯一ID,使用得话,记住它是唯一就行了。
之后声明了一个方法,方法名为getversion,下面定义了参数得类型。
接下来声明了一个signal,上面说过了,这个signal是在adaptor端使用的,后面得代码就可以看到。
我们有了XML文件以后,可以通过工具自动生成两个.h文件,一个是proxy端的.h,一个是adaptor端得.h。
输入如下命令:
dbusxx-xml2cpp test.xml --proxy=test_Proxy.h --adaptor=test_adaptor.h
后面得参数分别表示输入得xml文件,这里是test.xml,proxy端的.h文件名,这里是test_Proxy.h,adaptor端得.h得文件名,这里是test_adaptor.h。
接下来,我们分别来看看这两个.h文件得内容。
test_Proxy.h
/*
* This file was automatically generated by dbusxx-xml2cpp; DO NOT EDIT!
*/
#ifndef __dbusxx__ANI_proxy_h__PROXY_MARSHAL_H
#define __dbusxx__ANI_proxy_h__PROXY_MARSHAL_H
#include <dbus-c++/dbus.h>
#include <cassert>
namespace com {
namespace test {
class test_proxy
: public ::DBus::InterfaceProxy
{
public:
test_proxy()
: ::DBus::InterfaceProxy("com.test.interfacetest")
{
connect_signal(test_proxy,display, _display_stub);
}
public:
/* properties exported by this interface */
public:
/* methods exported by this interface,
* this functions will invoke the corresponding methods on the remote objects
*/
std::string getversion()
{
::DBus::CallMessage call;
call.member("getversion");
::DBus::Message ret = invoke_method (call);
::DBus::MessageIter ri = ret.reader();
std::string argout;
ri >> argout;
return argout;
}
public:
/* signal handlers for this interface
*/
virtual void display() = 0; //Note:这里是纯虚函数,需要在子类中实现,继承于test_proxy类的子类实现得这个函数则会在proxy端被调用。
private:
/* unmarshalers (to unpack the DBus message before calling the actual signal handler)
*/
void _display_stub(const ::DBus::SignalMessage &sig)
{
display();
}
};
} } }
#endif //__dbusxx__ANI_proxy_h__PROXY_MARSHAL_H
另一个.h文件也是类似得,都会有纯虚函数,在这个sample里面,是getversion()这个函数,则在adaptor端实现后,就会被proxy端得对应实例调用。
从上面得内容可以看到,其实我们有了XML文件以后,要做得工作就是完成其虚函数得实现。子类得具体代码我这里就不贴出来了,基本得C++语法就能解决。
实现虚函数以后,我们要做得就是将这些类实例化在进程中调用。
我这里得两个main.cpp如下:
proxy端:
#include "test_proxy_fill.h"
#include <signal.h>
void *runDispatcher(void *v);
void niam(int sig)
{
dispatcher.leave();
}
int main(int argc, char *argv[])
{
signal(SIGTERM, niam);
signal(SIGINT, niam);
DBus::default_dispatcher = &dispatcher;
DBus::_init_threading();
DBus::Connection bus = DBus::Connection::SessionBus();
test_proxy_fill test_proxy(bus, "/com/test", "com.test.test_interface");//test_proxy_fill是test_proxy得继承
std::string version = test_proxy.getversion(); //这边就相当于是进入到了adaptor端得进程内执行代码
dispatcher.enter();
return 1;
}
adaptor端:
#include "test_adaptor_fill.h"
int main(int argc, char *argv[])
{
DBus::_init_threading();
DBus::default_dispatcher = &dispatcher;
DBus::Connection bus = DBus::Connection::SessionBus();
// bus.request_name("com.test.testinterface");
test_adaptor_fill test_adaptor(bus,"/com/test","com.test.test_interface");//test_adaptor_fill是test_adaptor得继承
dispatcher.enter();
return 0;
}