DBUS是實質上一個適用於桌面應用的進程間的通訊機制,即所謂的IPC機制。適合在同一台機器,不適合於INTERNET的IPC機制。DBUS不是一個為所有可能的應用的通用的IPC機制,不支持其他IPC機制的很多特性。DBUS提供了一個低時延、低消耗的IPC通訊,因為它采用了二進制的數據交換協議,不需要轉換成文本化的數據進行交換,DBUS提供了面向多重對象系統的包裝,可以在原有的面向對象的應用框架下使用DBUS,不需要學習新的概念和規范等。
DBUS是支持一對一和多對多的對等通訊,在一對一的直接通訊時,兩個應用程序連接在一起,這是最簡單的工作方式。在多對多的通訊時,這就需要一個叫DBUS后台的角色去分轉,一個應用程序發消息給另外一個應用程序,先到達后台,再讓后台將信息發送到目的應用程序。在這里DBUS后台就充當着一個路由器的角色。
DBUS包含了系統更新通知,如插入新設備通知、新軟件安裝通知等,和桌面應用的交互協作能力,可以作為文件系統監控器和配置服務器。
Dbus由對象、消息、連接、Dbus后台幾部分組成。
對象是一個獨立的處理消息的實體。對象有一個或多個接口,在每個接口有一個或多個的方法,每個方法實現了具體的消息處理。在一對一的通訊中,對象通過一個連接直接和另一個客戶端應用程序連接起來。在多對多的通訊中,對象通過一個連接和Dbus后台進程連接起來。對象有一個路徑用於指明該對象的存放位置,消息傳遞時通過該路徑找到該對象。
客戶端應用是一個桌面應用程序,是請求消息的發起者。客戶端應用通過和自身的相連的一個連接將請求消息發送出去,也通過該連接接收回應的消息、錯誤消息、系統更新消息等。在一對一的通訊中,請求消息直接到達對象。在多對多的通訊中,請求消息先到達Dbus后台,Dbus后台將消息轉發到目的對象。
連接是一個雙向的消息傳遞通道。一個連接將對象和Dbus后台或客戶端應用連接起來,連接支持非阻塞式的異步消息發送和阻塞式的同步消息發送。消息通過連接到達目的端后,連接會將掛起在該連接上的進程喚醒,由該進程將消息取走。每個連接都有一個唯一的名字和可選的其他多個名字,用於在多對多通訊時指明消息的發送者和接收者。
連接基於操作系統提供的通訊端口實現消息的交換,現在基於的通訊端口有三種,分別是UNIX的socket、TCP/IP、管道(調試時用)。通訊端口擁有一個地址,服務器在這個地址上監聽,客戶端則連接到這個地址上。
消息是Dbus的IPC機制中的一個信息傳遞媒介。調用者將調用的方法、方法的參數打包進一個消息,接收者將方法和參數從消息中解包出來,執行這個方法調用。執行完后,將結果打包進返回消息中,返回給調用者。消息有四種類型,分別是方法調用消息、結果返回消息、錯誤消息、信號消息。這里的信號消息是主動發送的事件,如新設備插入、文件更改的事件等。
Dbus后台是在多對多通訊時用來轉發消息,管理連接的一個后台進程。每個Dbus后台都和多個連接關聯,其內部維護了連接名和連接實體的映射關系。Dbus后台就象一個路由器,將從發送者連接得到的消息轉發到由消息中的接收者連接名指定的接收者連接中。
Dbus后台有多個。有一個用於和系統通訊,監控系統更新事件,其類型為DBUS_BUS_SYSTEM的Dbus后台。每個桌面會話(session)有一個用於多個桌面應用之間相互通訊,其類型為DBUS_BUS_SESSION的Dbus后台。一般至少有兩個Dbus后台,一個系統用,一個桌面會話用。系統用的Dbus后台只能處理系統的消息,桌面會話用的Dbus后台只能處理桌面會話應用的消息。
1、客戶端。
在客戶端使用DBUS比較簡單,首先,從DBUS_BUS_SESSION類型的DBUS后台獲得一個連接,再從這個連接創建得到一個對象的代理,以后對對象的所有操作都將通過這個代理來完成。
得到服務代理后,可以在應用程序的各個地方通過對象代理的方法使用函數想對象發出一個方法調用的消息。請求對象的服務,可以發送異步的方法(異步服務),也可以發送同步方法(同步服務),方法是同步還是異步有對象定義。
2、服務端。
在服務器進程啟動后,調用函數dbus_g_object_type_install_info將對象的安裝信息結構告訴DBUS,隨后,從DBUS_BUS_SESSION類型的DBUS獲得一個連接,再從這個連接得到一個DBUS對象的代理。通過這個DBUS代理調用方法RequestName為這個連接得到一個命名,客戶端應用可以使用這個名字將請求消息發送到連接。接着,服務器進程創建一個指定類型的對象(glib對象)。
其中安裝信息由XML文件,通過dbus-binding-tool轉換成對象的頭文件。
3、消息。
消息由消息頭和消息體組成。消息頭由消息的固有字段信息組成。消息體由一串字符串值組成。消息體的每個字符串值的意義由消息頭中的描述指定,消息頭的長度必須是8的倍數,相應的,消息體由8的倍數處開始。
============================================================
D-Bus體系
有很多種IPC或者網絡通信系統,如:CORBA, DCE, DCOM, DCOP, XML-RPC, SOAP, MBUS, Internet Communications Engine (ICE)等等,可能會有數百種,dbus的目的主要是下面兩點:
1.在同一個桌面會話中,進行桌面應用程序之間的通訊
2.桌面程序與內核或者守護進程的通信。
Dbus是一套進程通信體系,它有以下幾層:
1.libdbus庫,提供給各個應用程序調用,使應用程序具有通信和數據交換的能力,兩個應用程序可以直接進行通信,就像是一條socket通道,兩個程序之間建立通道之后,就可以通訊了。
2.消息守護進程,在libdbus的基礎上創建,可以管理多個應用程序之間的通信。每個應用程序都和消息守護進程建立dbus的鏈接,然后由消息守護進程進行消息的分派。
3.各種包裝庫,有libdbus-glib,libdbus-qt等等,目的是將dbus的底層api進行一下封裝。
dbus中的消息由一個消息頭(標識是哪一種消息)和消息數據組成,比socket的流式數據更方便一些。bus daemon 就像是一個路由器,與各個應用程序進行連接,分派這些消息。bus daemon 在一台機器上有多個實例,第一個實例是全局的實例,類似於sendmail和或者apache,這個實例有很嚴格的安全限制,只接受一些特定的系統消息,用於系統通信。其他bus daemon是一些會話,用於用戶登錄之后,在當前會話(session)中進行的通訊。系統的bus daemon 和會話的bus daemon 是分開的,彼此不會互相影響,會話bus daemon 不會去調用系統的bus daemon 。
Native Objects and Object Paths
在不同的編程語言中,都定義了一些“對象”,如java中的java.lang.Object,GLIB中的GObject,QT中的QObject等等。D-BUS的底層接口,和libdbus API相關,是沒有這些對象的概念的,它提供的是一種叫對象路徑(object path),用於讓高層接口綁定到各個對象中去,允許遠端應用程序指向它們。object path就像是一個文件路徑,可以叫做/org/kde/kspread/sheets/3/cells/4/5等。
Methods and Signals
每個對象都有一些成員,兩種成員:方法(methods)和信號(signals),在對象中,方法可以被調用。信號會被廣播,感興趣的對象可以處理這個信號,同時信號中也可以帶有相關的數據。每一個方法或者信號都可以用一個名字來命名,如”Frobate” 或者 “OnClicked”。
Interfaces
每個對象都有一個或者多個接口,一個接口就是多個方法和信號的集合。dbus使用簡單的命名空間字符串來表示接口,如org.freedesktop.Introspectable。可以說dbus接口相當於C++中的純虛類。
Proxies
代理對象用於模擬在另外的進程中的遠端對象,代理對象像是一個正常的普通對象。d-bus的底層接口必須手動創建方法調用的消息,然后發送,同時必須手動接受和處理返回的消息。高層接口可以使用代理來替換這些,當調用代理對象的方法時,代理內部會轉換成dbus的方法調用,等待消息返回,對返回結果解包,返回給相應的方法。可以看看下面的例子,使用dbus底層接口編寫的代碼:
Message message = new Message("/remote/object/path", "MethodName", arg1, arg2);
Connection connection = getBusConnection();
connection.send(message);
Message reply = connection.waitForReply(message);
if (reply.isError()) {
} else {
Object returnValue = reply.getReturnValue();
}
使用代理對象編寫的代碼:
Proxy proxy = new Proxy(getBusConnection(), "/remote/object/path");
Object returnValue = proxy.MethodName(arg1, arg2);
客戶端代碼減少很多。
Bus Names
當一個應用程序連接上bus daemon時,daemon會分配一個唯一的名字給它。以冒號(:)開始,這些名字在daemon的生命周期中是不會改變的,可以認為這些名字就是一個IP地址。當這個名字映射到應用程序的連接上時,應用程序可以說擁有這個名字。同時應用可以聲明額外的容易理解的名字,比如可以取一個名字com.mycompany.TextEditor,可以認為這些名字就是一個域名。其他應用程序可以往這個名字發送消息,執行各種方法。
名字還有第二個重要的用途,可以用於跟蹤應用程序的生命周期。當應用退出(或者崩潰)時,與bus的連接將被OS內核關掉,bus將會發送通知,告訴剩余的應用程序,該程序已經丟失了它的名字。名字還可以檢測應用是否已經啟動,這往往用於只能啟動一個實例的應用。
Addresses
使用d-bus的應用程序既可以是server也可以是client,server監聽到來的連接,client連接到server,一旦連接建立,消息就可以流轉。如果使用dbus daemon,所有的應用程序都是client,daemon監聽所有的連接,應用程序初始化連接到daemon。
dbus地址指明server將要監聽的地方,client將要連接的地方,例如,地址:unix:path=/tmp/abcdef表明server將在/tmp/abcdef路徑下監聽unix域的socket,client也將連接到這個socket。一個地址也可以指明是TCP/IP的socket,或者是其他的。
當使用bus daemon時,libdbus會從環境變量中(DBUS_SESSION_BUS_ADDRESS)自動認識“會話daemon”的地址。如果是系統daemon,它會檢查指定的socket路徑獲得地址,也可以使用環境變量(DBUS_SESSION_BUS_ADDRESS)進行設定。
當dbus中不使用daemon時,需要定義哪一個應用是server,哪一個應用是client,同時要指明server的地址,這不是很通常的做法。
Big Conceptual Picture
要在指定的對象中調用指定的方法,需要知道的參數如下:
Address -> [Bus Name] -> Path -> Interface -> Method
bus name是可選的,除非是希望把消息送到特定的應用中才需要。interface也是可選的,有一些歷史原因,DCOP不需要指定接口,因為DCOP在同一個對象中禁止同名的方法。
Messages - Behind the Scenes
如果使用dbus的高層接口,就可以不用直接操作這些消息。DBUS有四種類型的消息:
1.方法調用(method call) 在對象上執行一個方法
2.方法返回(method return)返回方法執行的結果
3.錯誤(error)調用方法產生的異常
4.信號(signal)通知指定的信號發生了,可以想象成“事件”。
要執行 D-BUS 對象的方法,需要向對象發送一個方法調用消息。它將完成一些處理並返回一個方法返回消息或者錯誤消息。信號的不同之處在於它們不返回任何內容:既沒有“信號返回”消息,也沒有任何類型的錯誤消息。
每個消息都有一個消息頭,包含多個字段,有一個消息體,包含多個參數。可以認為消息頭是消息的路由信息,消息體作為一個載體。消息頭里面的字段包含發送的bus name,目標bus name,方法或者信號名字等,同時消息頭里面定義的字段類型規定了消息體里面的數據格式。例如:字符“i”代表了”32-bit integer”,“ii”就代表了消息體里面有兩個”32-bit integer”。
Calling a Method - Behind the Scenes
在dbus中調用一個方法包含了兩條消息,進程A向進程B發送方法調用消息,進程B向進程A發送應答消息。所有的消息都由daemon進行分派,每個調用的消息都有一個不同的序列號,返回消息包含這個序列號,以方便調用者匹配調用消息與應答消息。調用消息包含一些參數,應答消息可能包含錯誤標識,或者包含方法的返回數據。
方法調用的一般流程:
1.使用不同語言綁定的dbus高層接口,都提供了一些代理對象,調用其他進程里面的遠端對象就像是在本地進程中的調用一樣。應用調用代理上的方法,代理將構造一個方法調用消息給遠端的進程。
2.在DBUS的底層接口中,應用需要自己構造方法調用消息(method call message),而不能使用代理。
3.方法調用消息里面的內容有:目的進程的bus name,方法的名字,方法的參數,目的進程的對象路徑,以及可選的接口名稱。
4.方法調用消息是發送到bus daemon中的。
5.bus daemon查找目標的bus name,如果找到,就把這個方法發送到該進程中,否則,daemon會產生錯誤消息,作為應答消息給發送進程。
6.目標進程解開消息,在dbus底層接口中,會立即調用方法,然后發送方法的應答消息給daemon。在dbus高層接口中,會先檢測對象路徑,接口,方法名稱,然后把它轉換成對應的對象(如GObject,QT中的QObject等)的方法,然后再將應答結果轉換成應答消息發給daemon。
7.bus daemon接受到應答消息,將把應答消息直接發給發出調用消息的進程。
8.應答消息中可以包容很多返回值,也可以標識一個錯誤發生,當使用綁定時,應答消息將轉換為代理對象的返回值,或者進入異常。
bus daemon不對消息重新排序,如果發送了兩條消息到同一個進程,他們將按照發送順序接受到。接受進程並需要按照順序發出應答消息,例如在多線程中處理這些消息,應答消息的發出是沒有順序的。消息都有一個序列號可以與應答消息進行配對。
Emitting a Signal - Behind the Scenes
在dbus中一個信號包含一條信號消息,一個進程發給多個進程。也就是說,信號是單向的廣播。信號可以包含一些參數,但是作為廣播,它是沒有返回值的。
信號觸發者是不了解信號接受者的,接受者向daemon注冊感興趣的信號,注冊規則是”match rules”,記錄觸發者名字和信號名字。daemon只向注冊了這個信號的進程發送信號。
信號的一般流程如下:
1.當使用dbus底層接口時,信號需要應用自己創建和發送到daemon,使用dbus高層接口時,可以使用相關對象進行發送,如Glib里面提供的信號觸發機制。
2.信號包含的內容有:信號的接口名稱,信號名稱,發送進程的bus name,以及其他參數。
3.任何進程都可以依據”match rules”注冊相關的信號,daemon有一張注冊的列表。
4.daemon檢測信號,決定哪些進程對這個信號感興趣,然后把信號發送給這些進程。
5.每個進程收到信號后,如果是使用了dbus高層接口,可以選擇觸發代理對象上的信號。如果是dbus底層接口,需要檢查發送者名稱和信號名稱,然后決定怎么做。
Glib綁定接口在"dbus/dbus-glib.h"頭文件中定義。
dbus和glib的數據類型映射如下:
D-Bus basic type GType Free function Notes BYTE G_TYPE_UCHAR BOOLEAN G_TYPE_BOOLEAN INT16 G_TYPE_INT Will be changed to a G_TYPE_INT16 once
GLib has itUINT16 G_TYPE_UINT Will be changed to a G_TYPE_UINT16 once
GLib has itINT32 G_TYPE_INT Will be changed to a G_TYPE_INT32 once
GLib has itUINT32 G_TYPE_UINT Will be changed to a G_TYPE_UINT32 once
GLib has itINT64 G_TYPE_GINT64 UINT64 G_TYPE_GUINT64 DOUBLE G_TYPE_DOUBLE STRING G_TYPE_STRING g_free OBJECT_PATH DBUS_TYPE_G_PROXY g_object_unref The returned proxy does not have an interface set; use
dbus_g_proxy_set_interface to invoke methods
Container type mappings
dbus數據也有包容器類型,像DBUS_TYPE_ARRAY 和 DBUS_TYPE_STRUCT,dbus的數據類型可以是嵌套的,如有一個數組,內容是字符串的數組集合。
但是,並不是所有的類型都有普通的使用,DBUS_TYPE_STRUCT應該可以包容非基本類型的數據類型。glib綁定嘗試使用比較明顯的方式進行聲明。
D-Bus type signature Description GType C typedef Free function Notes as Array of strings G_TYPE_STRV char ** g_strfreev v Generic value container G_TYPE_VALUE GValue * g_value_unset The calling conventions for values expect that method callers have
allocated return values; see below.
同時定義了新的數組類型集合。
D-Bus type signature Description GType C typedef Free function Notes ay Array of bytes DBUS_TYPE_G_BYTE_ARRAY GArray * g_array_free au Array of uint DBUS_TYPE_G_UINT_ARRAY GArray * g_array_free ai Array of int DBUS_TYPE_G_INT_ARRAY GArray * g_array_free ax Array of int64 DBUS_TYPE_G_INT64_ARRAY GArray * g_array_free at Array of uint64 DBUS_TYPE_G_UINT64_ARRAY GArray * g_array_free ad Array of double DBUS_TYPE_G_DOUBLE_ARRAY GArray * g_array_free ab Array of boolean DBUS_TYPE_G_BOOLEAN_ARRAY GArray * g_array_free
定義了字典類型
D-Bus type signature Description GType C typedef Free function Notes a{ss} Dictionary mapping strings to strings DBUS_TYPE_G_STRING_STRING_HASHTABLE GHashTable * g_hash_table_destroy client端編寫
我們的程序在使用dbus的時候,首先需要連接上dbus,使用dbus_g_bus_get獲得dbus連接。然后可以創建代理對象。
需要調用方法的時候,可以有兩種方式:1.同步調用,使用dbus_g_proxy_call發送方法請求到遠端對象,dbus會阻塞等待遠端對象的回應,輸出參數里將會帶有相應的回應數據,以G_TYPE_INVALID作為終止符。2.異步調用,使用dbus_g_proxy_begin_call,它將返回一個DBusGPendingCall對象,可以使用dbus_g_pending_call_set_notify連接到自己的處理函授中。
可以使用dbus_g_proxy_add_signal 和 dbus_g_proxy_connect_signal來連接信號,dbus_g_proxy_add_signal用來聲明信號處理函數,屬於必須被調用的接口,dbus_g_proxy_connect_signal可以調用多次。
Generated Bindings
使用內置的xml文件,可以很方便地自動創建出易於使用的dbus代理對象。如下的一個xml文件描述了了一個方法:
“in”標識輸入參數,“out”標識輸出參數。
使用dbus-binding-tool工具來生成頭文件,如dbus-binding-tool –mode=glib-client my-object.xml > my-object-bindings.h,會產生如下的內聯函數原型:
gboolean
com_example_MyObject_many_args (DBusGProxy *proxy, const guint IN_x,
const char * IN_str, const gdouble IN_trouble,
gdouble* OUT_d_ret, char ** OUT_str_ret,
GError **error);
DBusGProxyCall*
com_example_MyObject_many_args_async (DBusGProxy *proxy, const guint IN_x,
const char * IN_str, const gdouble IN_trouble,
com_example_MyObject_many_args_reply callback,
gpointer userdata);
typedef void
(*com_example_MyObject_many_args_reply)
(DBusGProxy *proxy, gdouble OUT_d_ret, char * OUT_str_ret,
GError *error, gpointer userdata);所有函數的第一個參數都是DBusGProxy對象,一般是使用dbus_g_proxy_new_*函數創建出來的。客戶端發送方法請求可以增加標記,目前只有org.freedesktop.DBus.GLib.NoReply標記,dbus可以不要回應消息,沒有“out”參數,這樣運算速度會快一點。
server端的編寫
在GLib中,通過dbus表現出GObject,必須寫XML文件描述這個對象的方法等屬性。像上一篇文章中提到的例子:
一旦寫完XML,運行dbus-binding-tool工具,如 dbus-binding-tool –mode=glib-server my-object.xml > my-object-glue.h.
然后在本地代碼中include產生的頭文件,調用dbus_g_object_class_install_info進行類的初始化,傳遞對象和對象信息進去,如 dbus_g_object_type_install_info (COM_FOO_TYPE_MY_OBJECT, &com_foo_my_object_info);每個對象類都需要這樣做。
為了執行方法,需要定義一個C函數,如my_object_many_args,需要遵守的規則如下:
1.函數返回gboolean,true表示成功,false標識失敗。
2.第一個參數必須是對象實例的指針。
3.跟在實例指針后面的參數是方法的輸入參數。
4.輸入參數后面是輸出參數。
5.最后一個參數必須是GError **,如果函數返回失敗,必須使用g_set_error填充該錯誤參數。
如下的xml文件
對應的函數定義為:
gboolean
my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error);最后可以使用dbus_g_connection_register_g_object輸出一個對象,如
dbus_g_connection_register_g_object (connection,”/com/foo/MyObject”, obj);server端的聲明(Annotations):
org.freedesktop.DBus.GLib.CSymbol
org.freedesktop.DBus.GLib.Async
org.freedesktop.DBus.GLib.Const
org.freedesktop.DBus.GLib.ReturnVal首先需要啟動守護進程
dbus-daemon –system –print-pid –print-address
結果提示 Failed to start message bus: Could not get UID and GID for username “messagebus”
dbus需要有一個messagebus用戶,創建該用戶即可,useradd messagebus,問題解決。執行一個dbus測試程序,提示:D-Bus library appears to be incorrectly set up; failed to read machine uuid: Failed to open “/usr/var/lib/dbus/machine-id”: No such file or directory
沒有machine-id文件,查了一下,需要給它定義一個id,使用dbus-uuidgen >/usr/var/lib/dbus/machine-id
產生這個文件,該問題解決。再次執行測試程序,又有問題:Couldn’t connect to session bus: Failed to execute dbus-launch to autolaunch D-Bus session,看了幫助http://dbus.freedesktop.org/doc/dbus-launch.1.html
AUTOMATIC LAUNCHING一節,需要設置DBUS_SESSION_BUS_ADDRESS環境變量的值,先執行dbus-launch,獲得了DBUS_SESSION_BUS_ADDRESS值,再export一下,最后執行測試程序,OK了在dbus幫助中有一篇關於dbus-launch的文章,可以在腳本中啟動dbus-launch,同時自動設置DBUS_SESSION_BUS_ADDRESS環境變量,腳本文件rundbus如下:
if test -z "$DBUS_SESSION_BUS_ADDRESS" ; then
## if not found, launch a new one
eval `dbus-launch --sh-syntax --exit-with-session`
echo "D-Bus per-session daemon address is: $DBUS_SESSION_BUS_ADDRESS"
fi執行. rundbus即可。
基於DBus的應用程序可以是使用DBus Daemon的總線型結構,每個DBus的請求通過DBus Daemon轉發;或者是點對點的星型結構,Client與Server之間是直接的Peer2Peer的連接。這倆種結構各有優缺點:總線型的結構比較清晰,Server需要維護的連接較少,實際上只有一個與DBus Daemon相連的連接,廣播消息可以很容易的發送到各個Client;P2P形式的DBus通信中間因為少了DBus Daemon的中轉,因此性能更好,大約提升30%。
基於GLib提供的GBus實現基於以上倆種形態的DBus應用還是非常簡單的:
1. 准備工作
1.1 提供一個用於代碼生成的XML文件
這份XML數據在GDBus中稱為introspection data,用來描述提供服務的GObject的接口名與參數。用於gdbus-codegen可以使用這份XML文件生成在Client與Server側使用的代碼。對於總線型DBus應用和P2P型DBus應用,這份代碼是通用的。
1.2 編譯生成的代碼
生成的代碼需要分別鏈接到倆個進程中:帶有Skeleton字樣的代碼,運行在Server側;帶有Proxy字樣的代碼,運行在Client側。
gdbus-codegen 自動生成的代碼的規則可參考:http://people.freedesktop.org/~david/gio-gdbus-codegen-20110412/gdbus-codegen.html
2. 總線型
2.1 Server
2.1.1 提供一個基於Default Context的GLib Mainloop
2.1.2 調用g_bus_own_name在總線上注冊這個Server
2.1.3 提供on_name_acquried的回調函數,在回調函數中,創建一個skeleton對象,並調用g_dbus_interface_skeleton_export輸出到總線上
2.2 Client
2.2.1 提供一個基於Default Context的GLib Mainloop
2.2.2 調用dbus_proxy_new_sync獲取與Server的Skeleton對象相對應的Proxy對象,作為后續DBus方法調用的參數
A.Consider the following D-Bus Introspection XML.
<interface name="net.Corp.MyApp.Frobber"> <method name="HelloWorld"> <arg name="greeting" direction="in" type="s"/> <arg name="response" direction="out" type="s"/> </method> <signal name="Notification"> <arg name="icon_blob" type="ay"/> <arg name="height" type="i"/> <arg name="messages" type="as"/> </signal> <property name="Verbose" type="b" access="readwrite"/> </interface>
B.在server端static gboolean on_handle_hello_world (MyAppFrobber *interface, GDBusMethodInvocation *invocation, const gchar *greeting, gpointer user_data) { if (g_strcmp0 (greeting, "Boo") != 0) { gchar *response; response = g_strdup_printf ("Word! You said `%s'.", greeting); my_app_complete_hello_world (interface, invocation, response); g_free (response); } else { g_dbus_method_invocation_return_error (MY_APP_ERROR, MY_APP_ERROR_NO_WHINING, "Hey, %s, there will be no whining!", g_dbus_method_invocation_get_sender (invocation)); } return TRUE; } [...] interface = my_app_frobber_skeleton_new (); my_app_frobber_set_verbose (interface, TRUE); g_signal_connect (interface, "handle-hello-world", G_CALLBACK (on_handle_hello_world), some_user_data); [...] error = NULL; if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (interface), connection, "/path/of/dbus_object", &error)) { /* handle error */ }C.client 端
12345678910111213MyAppFrobber *proxy;
GError *error;
error = NULL;
proxy = my_app_frobber_proxy_new_for_bus_sync (
G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
"net.Corp.MyApp"
,
/* bus name */
"/net/Corp/MyApp/SomeFrobber"
,
/* object */
NULL,
/* GCancellable* */
&error);
/* do stuff with proxy */
g_object_unref (proxy);
3. P2P型
3.1 Server
3.1.1 提供一個基於Default Context的GLib Mainloop
3.1.2 調用g_dbus_server_start啟動一個Server
3.1.3 調用g_signal_connect,關聯callback到Server對象的"new-connection"信號上
3.1.4 提供callback,在callback中創建一個skeleton對象,並調用g_dbus_interface_skeleton_export輸出到這個新建立的連接上
3.2 Client
3.2.1 提供一個基於Default Context的GLib Mainloop
3.2.2 調用g_dbus_connection_new_for_address_sync建立一個到Server的連接
3.2.3 調用dbus_proxy_new_sync創建一個與Server側skeleton對象對應的Proxy對象,作為后續DBus方法調用的參數