歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux桌面 >> 用新型D-BUS與Linux桌面應用程序通訊

用新型D-BUS與Linux桌面應用程序通訊

日期:2017/2/27 14:13:00   编辑:Linux桌面

D-BUS 是一個大有前途的消息總線和活動系統,正開始深入地滲透到 Linux® 桌面之中。了解創建它的原因、它的用途以及發展前景。

D-BUS 本質上是 進程間通信(inter-process communication)(IPC)的一個實現。 不過,有一些特性使得 D-BUS 遠遠不是“只是另一個 IPC 實現”。有很多不同的 IPC 實現,因為每一個都定位於解決特定的明確定義的問題。CORBA 是用於面向對象編程中復雜的 IPC 的一個強大的解決方案。DCOP 是一個較輕量級的 IPC 框架,功能較少,但是可以很好地集成到 K 桌面環境中。SOAP 和 XML-RPC 設計用於 Web 服務,因而使用 HTTP 作為其傳輸協議。D-BUS 設計用於桌面應用程序和 OS 通信。

桌面應用程序通信

典型的桌面都會有多個應用程序在運行,而且,它們經常需要彼此進行通信。DCOP 是一個用於 KDE 的解決方案,但是它依賴於 Qt,所以不能用於其他桌面環境之中。類似的,Bonobo 是一個用於 GNOME 的解決方案,但是非常笨重,因為它是基於 CORBA 的。它還依賴於 GObject,所以也不能用於 GNOME 之外。 D-BUS 的目標是將 DCOP 和 Bonobo 替換為簡單的 IPC,並集成這兩種桌面環境。由於盡可能地減少了 D-BUS 所需的依賴,所以其他可能會使用 D-BUS 的應用程序不用擔心引入過多依賴。

桌面/操作系統通信

術語“操作系統”在這裡不僅包括內核,還包括系統後台進程。例如,通過使用 D-BUS 的 udev(Linux 2.6 中取代 devfs 的,提供動態 /dev 目錄),當設備(比如一個 USB 照相機)插入時會發放出一個信號。這樣可以更緊密地將硬件集成到桌面中,從而改善用戶體驗。

D-BUS 特性

D-BUS 有一些有趣的特性,使其像是一個非常有前途的選擇。

協議是低延遲而且低開銷的,設計得小而高效,以便最小化傳送的往返時間。另外,協議是二進制的,而不是文本的,這樣就排除了費時的序列化過程。由於只面向本地機器處理的使用情形,所以所有的消息都以其自然字節次序發送。字節次序在每個消息中聲明,所以如果一個 D-BUS 消息通過網絡傳輸到遠程的主機,它仍可以被正確地識別出來。

從開發者的角度來看,D-BUS 是易於使用的。有線協議容易理解,客戶機程序庫以直觀的方式對其進行包裝。

程序庫還設計用於為其他系統所包裝。預期,GNOME 將使用 GObject 創建包裝 D-BUS 的包裝器(實際上這些已經部分存在了,將 D-BUS 集成入它們的事件循環),KDE 將使用 Qt 創建類似的包裝器。由於 Python 具有面向對象特性和靈活的類型,已經有了具備類似接口的 Python 包裝器。

最後,D-BUS 正在 freedesktop.org 的保護下進行開發,在那裡,來自 GNOME、KDE 以及其他組織的對此感興趣的成員參與了設計與實現。

D-BUS 的內部工作方式

典型的 D-BUS 設置將由幾個總線構成。將有一個持久的 系統總線(system bus),它在引導時就會啟動。這個總線由操作系統和後台進程使用,安全性非常好,以使得任意的應用程序不能欺騙系統事件。還將有很多 會話總線(session buses),這些總線當用戶登錄後啟動,屬於那個用戶私有。它是用戶的應用程序用來通信的一個會話總線。當然,如果一個應用程序需要接收來自系統總線的消息,它不如直接連接到系統總線 —— 不過,它可以發送的消息將是受限的。

一旦應用程序連接到了一個總線,它們就必須通過添加 匹配器(matchers) 來聲明它們希望收到哪種消息。匹配器為可以基於接口、對象路徑和方法進行接收的消息指定一組規則(見後)。這樣就使得應用程序可以集中精力去處理它們想處理的內容,以實現消息的高效路由,並保持總線上消息的預期數量,以使得不會因為這些消息導致所有應用程序的性能下降並變得很慢。

對象

本質上,D-BUS 是一個對等(peer-to-peer)的協議 —— 每個消息都有一個源和一個目的。這些地址被指定為 對象路徑。概念上,所有使用 D-BUS 的應用程序都包括一組 對象,消息發送到或者發送自特定對象 —— 不是應用程序 —— 這些對象由對象路徑來標識。

另外,每個對象都可以支持一個或多個 接口(interfaces)。這些接口看起來類似於 Java 中的接口或者 C++ 中的純粹的虛類(pure virtual classes)。不過,沒有選項來檢查對象是否實現了它們所聲明的接口,而且也沒有辦法可以調查對象內部以使列出其支持的接口。接口用於名稱空間和方法名稱,因此一個單獨的對象可以有名稱相同而接口不同的多個方法。

消息

在 D-BUS 中有四種類型的消息:方法調用(method calls)、方法返回(method returns)、信號(signals)和錯誤(errors)。要執行 D-BUS 對象的方法,您需要向對象發送一個方法調用消息。它將完成一些處理並返回一個方法返回消息或者錯誤消息。信號的不同之處在於它們不返回任何內容:既沒有“信號返回”消息,也沒有任何類型的錯誤消息。

消息也可以有任意的參數。參數是強類型的,類型的范圍是從基本的非派生類型(布爾(booleans)、字節(bytes)、整型(integers))到高層次數據結構(字符串(strings)、數組( arrays)和字典(dictionaries))。

服務

服務(Services) 是 D-BUS 的最高層次抽象,它們的實現當前還在不斷發展變化。應用程序可以通過一個總線來注冊一個服務,如果成功,則應用程序就已經 獲得 了那個服務。其他應用程序可以檢查在總線上是否已經存在一個特定的服務,如果沒有可以要求總線啟動它。服務抽象的細節 —— 尤其是服務活化 —— 當前正處於發展之中,應該會有變化。

更多內容請看Linux應用 Linux應用技巧 日常應用管理專題,或

用例

盡管 D-BUS 相對較新,但是卻迅速地得到了采用。如前所述,可以構建具有 D-BUS 支持的 udev 以使得當熱插拔(hot-plug)設備時它可以發送一個信號。任何應用程序都可以偵聽這些事件並當接收到這些事件時執行動作。 例如,gnome-volume-manager 可以檢測到 USB 存儲棒的插入並自動掛載它;或者,當插入一個數碼相機時它可以自動下載照片。

一個更為有趣但很不實用的例子是 Jamboree 和 Ringaling 的結合。Jamboree 是一個簡單的音樂播放器,它具有 D-BUS 接口,以使得它可以被告知播放、到下一首歌、改變音量等等。Ringaling 是一個小程序,它打開 /dev/ttyS0(一個串行端口)並觀察接收到的內容。當 Ringaling 發現文本“RING”時,就通過 D-BUS 告知 Jamboree 減小音量。最終的結果是,如果您的計算機上插入了一個調制解調器,而且電話鈴響,則音樂音量就會為您減小。這 正是計算機所追求的!

代碼示例

現在,讓我們來接觸一些使用 D-BUS 代碼的示例。

dbus-ping-send.c 每秒通過會話總線發送一個參數為字符串“Ping!”的信號。我使用 Glib 來管理總線,以使得我不需要自己來處理總線的連接細節。

清單 1. dbus-ping-send.c

#include <glib.h>   #include <dbus/dbus-glib.h>      static gboolean send_ping (DBusConnection *bus);      int   main (int argc, char **argv)   {    GMainLoop *loop;    DBusConnection *bus;    DBusError error;       /* Create a new event loop to run in */    loop = g_main_loop_new (NULL, FALSE);       /* Get a connection to the session bus */    dbus_error_init (&error);    bus = dbus_bus_get (DBUS_BUS_SESSION, &error);    if (!bus) {     g_warning ("Failed to connect to the D-BUS daemon: %s", error.message);     dbus_error_free (&error);     return 1;    }       /* Set up this connection to work in a GLib event loop */    dbus_connection_setup_with_g_main (bus, NULL);    /* Every second call send_ping() with the bus as an argument*/    g_timeout_add (1000, (GSourceFunc)send_ping, bus);       /* Start the event loop */    g_main_loop_run (loop);    return 0;   }      static gboolean   send_ping (DBusConnection *bus)   {    DBusMessage *message;       /* Create a new signal "Ping" on the "com.burtonini.dbus.Signal" interface,     * from the object "/com/burtonini/dbus/ping". */    message = dbus_message_new_signal ("/com/burtonini/dbus/ping",       "com.burtonini.dbus.Signal", "Ping");    /* Append the string "Ping!" to the signal */    dbus_message_append_args (message,                 DBUS_TYPE_STRING, "Ping!",                 DBUS_TYPE_INVALID);    /* Send the signal */    dbus_connection_send (bus, message, NULL);    /* Free the signal now we have finished with it */    dbus_message_unref (message);    /* Tell the user we send a signal */    g_print("Ping!\n");    /* Return TRUE to tell the event loop we want to be called again */    return TRUE;   }

main 函數創建一個 GLib 事件循環,獲得會話總線的一個連接,並將 D-BUS 事件處理集成到 Glib 事件循環之中。然後它創建了一個名為 send_ping 間隔為一秒的計時器,並啟動事件循環。

更多內容請看Linux應用 Linux應用技巧 日常應用管理專題,或




Copyright © Linux教程網 All Rights Reserved