D-Bus是一個用於進程間通訊的系統。從架構上來講,分爲三部分:java
libdbus只支持one-to-one類型的鏈接,如同原始套接字那樣,區別是,發送的不是字節流(byte streams)而是消息。消息包含消息header和body,header標明信息類型,body包含消息主體內容。 Libdbus也能夠容許實現特定的傳輸通道,從而來完成好比像認證之類的應用細節。python
消息總線守護進程將D-bus上鍊接的全部程序構成一個輪形hub。輪子上的每個輪輻都是基於libdbus的一對一鏈接,鏈接了一個app。app經過輪輻向daemon發送消息,daemon在合適的時機將消息轉發到其餘已鏈接的app。daemon能夠理解爲一個路由器。編程
總線守護進程在系統中有多個實例。好比全局惟一的實例,一個如同sendmail或者Apache的系統daemon,對於接收什麼樣消息用來進程間通訊,有着很嚴格的安全要求(system bus?)。另一些daemon實例由用戶登陸時創建,用於該用戶的session中的app之間通訊。api
系統級的daemon和per-user daemon是分離的。session內的IPC不會影響系統級的message bus,反之亦然。安全
有許多技術用來實現IPC或者網絡信息傳遞,好比:CORBA, DCE, DCOM, DCOP, XML-RPC, SOAP, MBUS, Internet Communications Engine (ICE)。每一種都是針對特定種類的應用程序量身定作的。
Dbus爲兩種狀況而生:網絡
開發者在本身的編程架構中會定義object,一般基於一個基礎的類,好比 java.lang.Object, GObject, QObject, python's base Object, or whatever. 咱們稱爲native object。session
dbus協議和libdbus中的api不關心native object如何定義,而是提供了object path的概念。有了object path,上層的bindings就可以命名native object實例,而且容許遠程的app引用這些object。
object path如同文件系統中的文件路徑。好比,一個object能夠被命名爲/org/kde/kspread/sheets/3/cells/4/5。易於理解的路徑很棒,若有須要的話,是你也能夠命名爲諸如 /com/mycompany/c5yo817y0c1y1c5b。
名稱中指定命名空間是明智的作法,好比將路徑開頭設置爲你開發的domain名稱。這樣能夠保證同一進程中的不一樣模塊互不干擾。架構
每一個object都有成員(members),成員分爲方法(methods)和信號(signals)。方法(methods)是object能夠調用的一組操做,帶有輸入或者輸出參數。信號被廣播到任何一個對該信號感興趣的對象;信號也能夠承載數據。app
引用方法或者信號都是經過它們的名字,好比Frobate或者OnClickeddom
一個object只是一個或多個interface。一個interface中包含了一組方法和信號(methods and signals),概念如同 GLib or Qt or Java中的方法和信號。接口定義了object實例的類型。
dbus用簡單的命名空間字符串標識一個interface,好比org.freedesktop.Introspectable;大多數綁定會將這些interface直接映射到對應的編程語言結構,好比Java接口或者C++的純虛類。
代理(proxy)object是native object,用於表明其餘進程中的遠程object。底層的DBus API建立一個Methods call,發送,而後接收,處理這些回覆的消息。能夠把代理看作是一個普通的native object,可是當你調用代理中的方法,綁定(bindings)將該操做轉化爲
dbus Method call消息,等待遠端回覆消息,將返回值解包,而後返回到native 方法......
如下是一個僞代碼的例子,不使用proxy:
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 proxy = new Proxy(getBusConnection(), "/remote/object/path"); Object returnValue = proxy.MethodName(arg1, arg2);
每當app鏈接dbus daemon時,daemon爲app分配一個惟一的鏈接名字,以冒號開頭。一個bus name永遠指向同一個app,不會被複用。例如:34-907。冒號後面的數字除了它們的惟一性沒有意義。
app也能夠請求便於理解的名字。好比,com.mycompany.TextEditor。對應的object的路徑能夠爲/com/mycompany/TextFileManager,interface爲org.freedesktop.FileHandler
能夠將:34-907(unique name)看成是IP地址,com.mycompany.TextEditor看成是域名。com.mycompany.TextEditor映射 :34-907就如溝通mycompany.com映射到192.168.0.5。
除了路由消息,bus name還可用來追蹤app生命週期。當一個app退出或者crash時,操做系統內核(operating system kernel)會斷開message bus的鏈接,而後message bus發送消息通知
其餘app該name已經失去owner了。經過追蹤這些notification,能夠檢測其餘app的生命週期。
Bus name名字還能夠檢測應用是否已經啓動,這能夠用來實現單實例啓動程序。
應用做爲dbus的server或者client,server監聽來自client的鏈接,client鏈接到server。一旦鏈接創建,它就是一個對稱的消息流。
Dbus address指明server去哪監聽,client去哪裏鏈接。例如,地址unix:path=/tmp/abcdef指明瞭server將監聽一個Unix socket,路徑是/tmp/abcdef, client將鏈接到這個socket。
address也能指定TCP/IP sockets,或者其餘類型的傳輸方式。
Big Conceptual Picture
把上面的概念組合起來獲得如下流程:
Address -> [Bus Name] -> Path -> Interface -> Method
Dbus工做原理是在兩個進程之間發送消息,若是工做在至關上層的binging中,是不會直接處理消息的。
四種類型消息:
每一個消息有一個消息頭,包含field和body和桉樹。能夠將header看成消息的路由信息,body看成消息體。header可能包含如下信息:發送方bus name,目的地的busname,調用的方法或者信號,等等。
header中有一個描述body中值的類型的field。好比,字母i岱廟32位整數,ii標識body有兩個32位整數。
一個方法調用(method call)由兩條消息組成,一個方法調用消息從進程A發送給進程B,對應的方法返回消息從進程B發送給進程A,發送和返回消息都要通過bus daemon路由。
每一個call消息包含一串獨有的數字,reply消息也包含這個數字以便和發送方匹配。
發送消息帶有參數,會傳遞給遠程method,回覆消息可能包含一個錯誤或者遠程method返回的數據。
Dbus中的方法調用流程以下:
Bus daemon不會爲消息排序,也就是說,若是發送兩條method call消息到同一接收方,接收的順序與發送順序相同。接收方不必定按照接收的順序來回復消息。好比,接收方可能在兩個不一樣的線程中處理method call,哪一個消息先處理完就先返回。
信號由一條消息組成,從一個進程發送到另外一個或多個進程。也就是說,信號是單向的廣播。信號可能包含參數(數據部分),由於它是一個廣播,沒有返回值。
信號的發送者不知道接受者是誰。接收者爲了接收信號須要向bus daemon進行註冊,基於「match rules」,這些規則包含了發送者和接受者的名字。Bus daemon只將信號發送給對該信號感興趣的接收者。
信號的流程大體以下:
Dbus objects支持org.freedesktop.DBus.Introspectable,dbus的標準接口,無需參數,返回一個XML字符串,描述了接口,方法,信號。