dbus例項講解(一):初次見面
http://blog.csdn.net/fmddlmyy/archive/2008/12/23/3585730.aspx
網上有不少介紹dbus的文章。本文的目標是補充一些簡單的例子。
1、dbus是什麼東西?
網上有一篇叫“D-Bus Tutorial”的文章,流傳較廣。不少介紹dbus的資料,都引用了其中的段落。其實相對於這篇文章,我建議大家直接讀“D-Bus Specification”,篇幅不算長,文字也不算枯燥。
D-Bus是針對桌面環境優化的IPC(interprocess communication )機制,用於程序間的通訊或程序與核心的通訊。最基本的D-Bus協議是一對一的通訊協議。但在很多情況下,通訊的一方是訊息匯流排。訊息匯流排是一個特殊的應用,它同時與多個應用通訊,並在應用之間傳遞訊息。下面我們會在例項中觀察訊息匯流排的作用。訊息匯流排的角色有點類似與X系統中的視窗管理器,視窗管理器既是X客戶,又負責管理視窗。
支援dbus的系統都有兩個標準的訊息匯流排:系統匯流排和會話匯流排。系統匯流排用於系統與應用的通訊。會話匯流排用於應用之間的通訊。網上有一個叫d-feet的python程式,我們可以用它來觀察系統中的dbus世界。
圖1、由d-feet觀察到的D-Bus世界
D-Bus是一個程式。它提供了API。但我們一般不會直接使用dbus的介面。dbus-glib是GTK版本的dbus介面封裝。本文假設讀者安裝了dbus-glib,我安裝的是dbus-glib-0.76。後面還會看到,通過python操縱dbus是多麼簡單。
2、D-Bus的基本概念
2.1、從例子開始
我寫了一個最簡單的dbus伺服器,它通過dbus提供了一個加法的介面。大家可以
./autogen.sh ./configure make
然後在src目錄執行:
./example-service
這時再執行d-feet,連線session bus,在“Bus Name”視窗會看到一個叫“org.fmddlmyy.Test”連線名。
圖2、提供D-Bus服務的org.fmddlmyy.Test
選擇“org.fmddlmyy.Test”,在右側視窗點選展開“Object Paths”->“/TestObj”->“Interfaces”->“org.fmddlmyy.Test.Basic”->“Methods”,可以看到一個Add方法。雙擊Add方法,彈出下面這個對話方塊:
圖3、通過D-Bus介面計算1+2=3
在Parameters視窗輸入“1,2”,點選“Execute”按鈕,然後在“Output”視窗我們看到了輸出結果。我們剛剛建立了一個dbus服務並呼叫了它。
2.2、名詞
我們來解釋一下d-feet中出現的名詞。
2.2.1、Bus Name
可以把Bus Name理解為連線的名稱,一個Bus Name總是代表一個應用和訊息匯流排的連線。有兩種作用不同的Bus Name,一個叫公共名(well-known names),還有一個叫唯一名(Unique Connection Name)。
2.2.1.1、可能有多個備選連線的公共名
公共名提供眾所周知的服務。其他應用通過這個名稱來使用名稱對應的服務。可能有多個連線要求提供同個公共名的服務,即多個應用連線到訊息匯流排,要求提供同個公共名的服務。訊息匯流排會把這些連線排在連結串列中,並選擇一個連線提供公共名代表的服務。可以說這個提供服務的連線擁有了這個公共名。如果這個連線退出了,訊息匯流排會從連結串列中選擇下一個連線提供服務。公共名是由一些圓點分隔的多個小寫標誌符組成的,例如“org.fmddlmyy.Test”、“org.bluez”。
2.2.1.2、每個連線都有一個唯一名
當應用連線到訊息匯流排時,訊息匯流排會給每個應用分配一個唯一名。唯一名以“:”開頭,“:”後面通常是圓點分隔的兩個數字,例如“:1.0”。每個連線都有一個唯一名。在一個訊息匯流排的生命期內,不會有兩個連線有相同的唯一名。擁有公眾名的連線同樣有唯一名,例如在前面的圖中,“org.fmddlmyy.Test”的唯一名是“:1.17”。
有的連線只有唯一名,沒有公眾名。可以把這些名稱稱為私有連線,因為它們沒有提供可以通過公共名訪問的服務。 d-feet介面上有個“Hide Private”按鈕,可以用來隱藏私有連線。
2.2.2、Object Paths
Bus Name確定了一個應用到訊息匯流排的連線。在一個應用中可以有多個提供服務的物件。這些物件按照樹狀結構組織起來。每個物件都有一個唯一的路徑(Object Paths)。或者說,在一個應用中,一個物件路徑標誌著一個唯一的物件。
“org.fmddlmyy.Test”只有一個叫作“/TestObj”的物件。圖1中的“org.bluez”有多個物件路徑。
2.2.3、Interfaces
通過物件路徑,我們找到應用中的一個物件。每個物件可以實現多個介面。例如:“org.fmddlmyy.Test”的“/TestObj”實現了以下介面:
- org.fmddlmyy.Test.Basic
- org.freedesktop.DBus.Introspectable
- org.freedesktop.DBus.Properties
後面講程式碼時會看到,我們在程式碼中其實只實現了“org.fmddlmyy.Test.Basic”這個介面。介面“org.freedesktop.DBus.Introspectable”和“org.freedesktop.DBus.Properties”是訊息匯流排提供的標準介面。
2.2.4、Methods和Signals
介面包括方法和訊號。例如“org.fmddlmyy.Test”的“/TestObj”物件的“org.fmddlmyy.Test.Basic”介面有一個Add方法。後面的例子中我們會介紹訊號。
標準介面“org.freedesktop.DBus.Introspectable”的Introspect方法是個很有用的方法。類似於Java的反射介面,呼叫Introspect方法可以返回介面的xml描述。我們雙擊 “org.fmddlmyy.Test”->“/TestObj”->“org.fmddlmyy.Test.Basic”->“org.freedesktop.DBus.Introspectable”的Introspect方法。這個方法沒有輸入引數,我們直接點選“Execute”按鈕,你在“Output”視窗看到了什麼?
圖4、呼叫Introspect方法
後面我們會用另一種方式呼叫Introspect方法。
2.3 小結
“org.fmddlmyy.Test”->“/TestObj”->“org.fmddlmyy.Test.Basic”->“org.freedesktop.DBus.Introspectable”的Introspect方法,這個描述是不是很麻煩。其實前面還要加上“session bus”。
後面在看客戶端的C程式碼時,我們會看到同樣的過程:用dbus_g_bus_get得到到session bus的連線。在這個連線上用dbus_g_proxy_new_for_name函式獲得到擁有指定公共名的連線的指定物件的指定介面的代理。最後,用dbus_g_proxy_call函式通過介面代理呼叫介面提供的方法。
3 下集預告
d-feet雖然很方便,但它使用了python的gtk模組,在一些嵌入式環境可能使用不了。後面會看到,用一個叫dbus-send的命令列工具,或者寫幾行python指令碼都可以完成同樣的工作。我們還會用一個叫dbus-monitor的命令列工具觀察dbus呼叫過程中究竟發生了什麼?