對libdbus庫函數使用的理解


 

1.D-BUS 的內部工作方式

典型的D-BUS設置將由幾個總線構成。將有一個持久的系統總線(system bus),它在引導時就會啟動。這個總線由操作系統和后台進程使用,安全性非常好,以使得任意的應用程序不能欺騙系統事件。還將有很多會話總線(session buses),這些總線當用戶登錄后啟動,屬於那個用戶私有。它是用戶的應用程序用來通信的一個會話總線。如果一個應用程序需要接收來自系統總線的消息,可以直接連接到系統總線 —— 不過,它可以發送的消息將是受限的。只有Linux內核、Linux桌面環境和權限較高的程序才能向系統總線寫入消息,以此保障系統安全性,防止有惡意進程假冒Linux發送消息。 

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

1.1對象

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

每個對象都可以支持一個或多個接口(interfaces)。這些接口看起來類似於 Java 中 的接口或者 C++ 中的純粹的虛類(pure virtual classes)。一個接口就是多個方法和信號的集合。dbus使用簡單的命名空間字符串來表示接口,如org.freedesktop.Introspectable

1.2消息

D-BUS 中有四種類型的消息:

      1.方法調用(method call) 在對象上執行一個方法

      2.方法返回(method reply)返回方法執行的結果

      3.錯誤(error)調用方法產生的異常

      4.信號(signal)通知指定的信號發生了,可以想象成事件

要執行 D-BUS 對象的方法,您需要向對象發送一個”methodcall”消息。它將完成一些處理並返回一個”methodReply”消息或者”error”消息。信號的不同之處在於它們不返回任何內容:既沒有methodReply”消息,也沒有 任何類型的”error”消息。

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

2.D-Bus low-level API的使用

2.1建立服務的流程

建立一個dbus連接之后 -- dbus_bus_get()為這個連接注冊監視函數--dbus_connection_set_watch_functions(),為這個連接注冊超時函數--dbus_connection_set_timeout_functions(),為這個連接注冊消息處理函數--dbus_connection_add_filter(),為這個dbus連接(DbusConnection)起名 -- dbus_bus_request_name(),這個名字將會成為我們在后續進行遠程調用的時候的服務名,為這個連接添加匹配器dbus_bus_add_match(),將對象路徑注冊到總線,然后我們進入文件描述符讀寫就緒狀態監聽循環。在循環中,我們從總線上取出消息 -- dbus_watch_handle(),然后通過dbus_connection_dispatch()分發給前面通過dbus_connection_add_filter()注冊的消息處理函數,並通過比對消息中的方法接口名和方法名 -- dbus_message_is_method_call(),如果一致,那么我們跳轉到相應的處理中去。在相應的處理中,我們會從消息中取出遠程調用的參數。並且建立起回傳結果的通路 -- reply_to_method_call()。回傳動作本身等同於一次不需要等待結果的遠程調用。

2.2發送信號的流程:

建立一個dbus連接之后,為這個dbus連接起名,建立一個發送信號的通道,注意,在建立通道的函數中,需要我們填寫該信號的接口名和信號名 -- dbus_message_new_signal()。然后我們把信號對應的相關參數壓進去 -- dbus_message_iter_init_append(); dbus_message_iter_append_basic()。然后就可以啟動發送了 -- dbus_connection_send(); dbus_connection_flush

2.3 進行一次遠程調用的流程:

建立好dbus連接之后,為這dbus連接命名,申請一個遠程調用通道 -- dbus_message_new_method_call(),注意,在申請遠程調用通道的時候,需要填寫服務器名,本次調用的接口名,和本次調用名(方法名)。壓入本次調用的參數 -- dbus_message_iter_init_append(); dbus_message_iter_append_basic(),實際上是申請了一個首地址,我們就是把我們真正要傳的參數,往這個首地址里面送(送完之后一般都會判斷是否內存越界了)。然后就是啟動發送調用並釋放發送相關的消息結構 -- dbus_connection_send_with_reply()。這個啟動函數中帶有一個句柄。我們馬上會阻塞等待這個句柄給我們帶回總線上回傳的消息。當這個句柄回傳消息之后,我們從消息結構中分離出參數。用dbus提供的函數提取參數的類型和參數 -- dbus_message_iter_init(); dbus_message_iter_next(); dbus_message_iter_get_arg_type(); dbus_message_iter_get_basic()。也就達成了我們進行本次遠程調用的目的了。

2.4信號接收流程:

建立一個dbus連接之后,為這個dbus連接起名,為我們將要進行的消息循環添加匹配條件(就是通過信號名和信號接口名來進行匹配控制的) -- dbus_bus_add_match()。我們進入等待循環后,只需要對信號名,信號接口名進行判斷就可以分別處理各種信號了。在各個處理分支上。我們可以分離出消息中的參數。對參數類型進行判斷和其他的處理。

 

 

 

 

3.D-Bus low-level public API的使用理解

3.1關於DBusConnection的理解

DBusConnection代表着和總線或者另外一個應用的連接,通過它可以來來發送和接收消息,通過函數dbus_bus_get()函數,來連接到一個已經公布名稱的總線,進而獲取一個DBusConnection連接。DBusConnection可以看做是一個維護着接收和發送的兩個消息隊列,它基於SOCKET進行數據的傳送。

DBusConnection上通過DBusWatchDBusTimeout兩個對象來決定何時進行消息接收、消息發送和消息分發的處理操作,通過dbus_connection_dispatch()函數,來處理接收消息隊列最頂端的一個消息,dbus_connection_dispatch()函數內部會執行已經注冊過的消息處理函數(在resourcemanager程序中是msg_filter()函數)。刪除接收消息隊列中這個處理過的消息,然后返回。

dbus_connection_get_dispatch_status()函數指示是否隊列中需要等待處理的消息。

為了達到對消息隊列的異步處理,我們需要兩個函數dbus_connection_set_watch_functions(), dbus_connection_set_timeout_functions() 來整合DBusConnection到我們函數自己的主循環中去(在resourcemanger程序中是bus_watch_daemon)。如果不需要異步處理的話,可以忽略對象DBusWatch, DBusTimeout以及函數dbus_connection_dispatch().然后就需要使用函數 dbus_connection_read_write_dispatch().

當使用函數dbus_connection_send()發送消息的時候,消息被添加到DBusConnection的發送隊列中去,如果執行dbus_connection_flush()函數,那么進程將被阻塞,直到發送隊列中的消息被通過SOCKET完全傳送出去;如果不執行該函數,則會在下次主循環執行dbus_watch_handle的時候被通過SOCKET傳送出去。

當連接被斷開的時候,會在 interface DBUS_INTERFACE_LOCAL, path DBUS_PATH_LOCAL上接收到“Disconnected”信號,在連接被斷開以前,必須保持對DBusConnection的引用。

3.2 關於DBusMessage的理解

消息DBusMessage通過DBusConnection進行發送和接收。

消息具有消息頭,消息頭的屬性通過函數dbus_message_get_type()來獲取,消息包含的消息頭,指示了消息的來源 消息的目標地 方法調用或信號調用 以及其他信息,通過函數dbus_message_get_member()來獲取。也可以通過更加簡便的方式來獲取,包括

dbus_message_is_method_call(),判斷是否是方法調用 

dbus_message_is_signal(),判斷是否是信號消息

dbus_message_is_error()判斷是否是出錯消息 

消息攜帶的參數,通過dbus_message_get_signature()來獲取簽名,對於簡單的參數通過dbus_message_get_args()來獲取,對於復雜的結構體參數,通過DBusMessageIter來獲得。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM