2017/09/13

[Linux] Ubuntu之中Inter-Process Communication 利用sd-bus (D-bus)來實現

上次討論過在OpenWrt之中的IPC服務ubus,所以這次要來探討更大的系統Ubuntu之中所使用的IPC,也就是D-Bus。關於ubus的使用,有興趣可以參考這篇


從D-Bus的Wiki可以看到洋洋灑灑的介紹,但是這裡想要討論的是關於D-Bus的各種Implementations。目前比較常看到的有libdbus、sd-bus和GDBus等等,大體而言這三個都有依照D-Bus的標準來實作,只是三者在函式實作的等級不一樣。




libdbus可以算是最低階的API,但也因為低階,所以使用上就得自己處理很多細節。GDBus算是最高階的,可以省掉很多設定。但是這次主要想探討的事sd-bus,因為根據網路上的資料,這應該是幾個D-Bus實作之中,速度最快的。有興趣可以參考這篇資料。再者,網路上能夠參考資料並不多,所以就嘗試把自己測試過的結果給記錄下來。

sd-bus最常看到的參考資料是這個網站。對於一些概念跟測試方法、範例都寫得很詳盡。

sd-bus之中比較重要的概念有兩個:
1. method: 用以呼叫執行及回傳結果
2. signal: 用以通知其他程序,對於自身狀態的改變或者其他資料等等

所以在架構上,method會長這樣
從demoA呼叫demoB的method,並且demoB做完之後,把結果回傳給demoA。

而signal則是
demoB如果有什麼更新資料,可以透過signal送給D-Bus;而demoA本身透過sd_bus_add_match()這個函式,可以獲取相符合的signal資料。

所以兩個程式在實作的概念上,有幾個步驟要做

連結到session Bus,system Bus通常都還要配合權限的設定,權限的檔案可以參考/etc/dbus-1/system.d/底下的檔案。
 r = sd_bus_open_user(&manager->bus);
加入整個物件的內容,包含methods, signals
 r = sd_bus_add_object_vtable(
  manager->bus,
  &manager->slot,
  OBJECT_PATH,  /* object path */
  INTERFACE_NAME,   /* interface name */
  service_vtable,
  NULL);
加入所要獲取的signals
 r = sd_bus_add_match(
  manager->bus, 
  NULL,
  "type='signal',"
  "sender='com.cybernut.demoB',"
  "interface='com.cybernut.demoB.ServiceB',"
  "member='SignalTestB',"
  "path='/com/cybernut/demoB/ServiceB'",
  match_signal_test,
  NULL);
呼叫method
 r = sd_bus_call_method(
  manager->bus,
  "com.cybernut.demoA",
  "/com/cybernut/demoA/ServiceA",
  "com.cybernut.demoA.ServiceA",
  "Multiply",
  &error,
  &m_fr_demoA,
  "xx",
  x,
  y);
送出signal
 r = sd_bus_emit_signal(
  manager->bus,
  OBJECT_PATH, /* object path */
  INTERFACE_NAME, /* interface name */
  "SignalTestB",
  "x", test_message);

好用的小工具: D-Feet
打開D-Feet,選擇session Bus,然後輸入service names。可以找到自己寫的程式。

並且可以看到各個介面,包含methods和signals。


執行結果
持續收到demoB的signals。

每隔5秒,送出signal給demoA。

另外一個demo case:
從D-Feet去呼叫DemoB的method,接著由demoB呼叫demoA的method;在執行完之後,由demoA回傳結果給demoB,再由demoB回傳給D-Feet。


整包程式碼,參考GitHub

沒有留言:

張貼留言