因為以后工作用的到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;
}