D-BUS基礎編程

引用自:

 http://dash1982.javaeye.com/?show_full=true

 

第十二章 自由桌面項目

 

    典型的桌面都會有多個應用程序在運行,而且,它們經常需要彼此進行通信。DCOP是一個用於KDE的 解決方案,但是它依賴於Qt,所以不能用於其他桌面環境之中。類似的,Bonobo是一個用於GNOME的解決方案,但是非常笨重,因爲它是基於 CORBA的。它還依賴於GObject,所以也不能用於GNOME之外。 D-BUS的目標是將DCOP和Bonobo替換爲簡單的IPC,並集成這兩種桌面環境。由於儘可能地減少了D-BUS所需的依賴,所以其他可能會使用 D-BUS的應用程序不用擔心引入過多依賴。
    D-BUS屬於FreeDesktop.org項目的一部分。bus守護進程,沒有使用常用的二進制字節流,而是使用了二進制消息的概念,消息由消息頭和相應的數據組成。
    操作系統的概念: 包括內核、系統守護進程和進程。D-BUS的設計目的:方便同一個桌面會話中的多個應用程序之間的通信;有助於桌面應用程序和操作系統之間的通信。專門用於桌面的,可能不適用於其他方面的應用。
    D-BUS總線分類:系統總線和會話總線。
    持久的系統總線(system bus),它在引導時就會啓動。這個總線由操作系統和後臺進程使用,安全性非常好,以使得任意的應用程序不能欺騙系統事件。
    還將有很多會話總線(session buses),這些總線當用戶登錄後啓動,屬於那個用戶私有。它是用戶的應用程序用來通信的一個會話總線。當然,如果一個應用程序需要接收 來自系統總線的消息,它不如直接連接到系統總線----不過,它可以發送的消息將是受限的。

D-BUS基礎
    API沒有綁定到任何一個特定的語言或框架。例如有Glib/Qt/python/C#的D-Bus綁定。

使用D-BUS發送一個消息到總線

C代碼
  1. #include <dbus/dbus.h>  //要使用dbus則必須包含此文件   
  2. #include <stdlib.h>   
  3. #include <stdio.h>   
  4.   
  5. /*  
  6. cc $(pkg-config --cflags --libs dbus-glib-1) -o dbus-send-hello dbus-send-hello.c && ./dbus-send-hello  
  7. */   
  8.   
  9. int  main ( int  argc,  char  *argv[])  
  10. {  
  11.         DBusError dberr;  
  12.         DBusConnection *dbconn;  
  13.         DBusMessage *dbmsg;  
  14.         char  *text;  
  15.   
  16.         dbus_error_init (&dberr);  
  17.         dbconn = dbus_bus_get (DBUS_BUS_SESSION, &dberr);  //代表連接到會話總線,如果需要連接到   
  18.        //系統總線,簡單把DBUS_BUS_SESSION替換爲DBUS_BUS_SYSTEM即可。但是有麻煩,因爲   
  19.      //系統總線對可以連接到它的用戶有限制。可能需要提供一個.service文件指明能連接到某一個指定服務器的權限   
  20.         if  (dbus_error_is_set (&dberr)) {  
  21.                 fprintf (stderr, "getting session bus failed: %s/n" , dberr.message);  
  22.                 dbus_error_free (&dberr);  
  23.                 return  EXIT_FAILURE;  
  24.         }  
  25.   
  26.         dbmsg = dbus_message_new_signal ("/com/wiley/test" ,  
  27.                                          "com.wiley.test" ,  
  28.                                          "TestSignal" );  
  29. /* 函數原型是  
  30. DBusMessage* dbus_message_new_signal (const char *path,    
  31.                       const char *interface,    
  32.                      const char *name) */   
  33.   
  34.         if  (dbmsg == NULL) {  
  35.                 fprintf (stderr, "Could not create a new signal/n" );  
  36.                 return  EXIT_FAILURE;  
  37.         }  
  38.   
  39.         text = "Hello World" ;  
  40.         dbus_message_append_args (dbmsg, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID);  
  41.   
  42.         dbus_connection_send (dbconn, dbmsg, NULL);  
  43.         printf ("Sending signal to D-Bus/n" );  
  44.   
  45.         dbus_message_unref (dbmsg);  
  46.   
  47.         dbus_connection_unref (dbconn);  
  48.   
  49.         return  EXIT_SUCCESS;  
  50. }  

  DBus是與應用程序中的對象而不是應用程序自身進行通信。在GLIB應用程序中,意味着是與GObject及其派生對象通信。應用程序中,這些對象以應 用程序地址空間中內存地址的形式傳遞,將這些內存地址傳遞給其他應用程序是沒有意義的。D-BUS傳遞對象路徑,對象路徑類似於文件系統路徑,例如 /org/foo/bar等表示Foo Bar應用程序的頂層對象路徑。並不是必需的,但是這樣做可以避免產生衝突。

    發送給一個對象的消息類型:

    方法調用(method calls)、方法返回(method returns)、信號(signals) 和錯誤(errors)。

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

C代碼
  1.  dbus_int32_t v_INT32 = 42;  
  2.  const   char  *v_STRING =  "Hello World" ;  
  3.  dbus_message_append_args (message,  
  4.                            DBUS_TYPE_INT32, &v_INT32,  
  5.                            DBUS_TYPE_STRING, &v_STRING,  
  6.                            DBUS_TYPE_INVALID);  
  7. const  dbus_int32_t array[] = { 1, 2, 3 };  
  8.  const  dbus_int32_t *v_ARRAY = array;  
  9.  dbus_message_append_args (message,  
  10.                            DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &v_ARRAY, 3,  
  11.                            DBUS_TYPE_INVALID);  
 
C代碼
  1. dbus_bool_t dbus_connection_send    (   DBusConnection *     connection,  
  2.         DBusMessage *   message,  
  3.         dbus_uint32_t *     serial     
  4.     )     
  5.        connection   the connection.  
  6.     message     the message to write.  
  7.     serial  return  location  for  message serial, or NULL  if  you don't care   

 dbus-get-hello.c :

C代碼
  1. #include <dbus/dbus.h>   
  2. #include <stdlib.h>   
  3. #include <stdio.h>   
  4.   
  5. /*  
  6. cc $(pkg-config --cflags --libs dbus-glib-1) -o dbus-get-hello dbus-get-hello.c && ./dbus-get-hello  
  7. */   
  8.   
  9. static  DBusHandlerResult  
  10. filter_func (DBusConnection *connection,  
  11.              DBusMessage *message,  
  12.              void  *user_data)  
  13. {  
  14.         dbus_bool_t handled = FALSE;  
  15.         char  *signal_text = NULL;  
  16.   
  17.         if  (dbus_message_is_signal (message,  "com.wiley.test" "TestSignal" )) {  
  18.                 DBusError dberr;  
  19.   
  20.                 dbus_error_init (&dberr);  
  21.                 dbus_message_get_args (message, &dberr, DBUS_TYPE_STRING, &signal_text, DBUS_TYPE_INVALID);  
  22.                 if  (dbus_error_is_set (&dberr)) {  
  23.                         fprintf (stderr, "Error getting message args: %s" , dberr.message);  
  24.                         dbus_error_free (&dberr);  
  25.                 } else  {  
  26.                         DBusConnection *dbconn = (DBusConnection*) user_data;  
  27.   
  28.                         printf ("Received TestSignal with value of: '%s'/n" , signal_text);  
  29.   
  30.                         handled = TRUE;  
  31.                 }  
  32.         }  
  33.   
  34.         return  (handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED);  
  35. }  
  36.   
  37.   
  38. int  main ( int  argc,  char  *argv[])  
  39. {  
  40.         DBusError dberr;  
  41.         DBusConnection *dbconn;  
  42.   
  43.         dbus_error_init (&dberr);  
  44.         dbconn = dbus_bus_get (DBUS_BUS_SESSION, &dberr);  
  45.         if  (dbus_error_is_set (&dberr)) {  
  46.                 fprintf (stderr, "getting session bus failed: %s/n" , dberr.message);  
  47.                 dbus_error_free (&dberr);  
  48.                 return  EXIT_FAILURE;  
  49.         }  
  50.   
  51.         dbus_bus_request_name (dbconn, "com.wiley.test" ,  
  52.                                DBUS_NAME_FLAG_REPLACE_EXISTING, &dberr);  
  53.         if  (dbus_error_is_set (&dberr)) {  
  54.                 fprintf (stderr, "requesting name failed: %s/n" , dberr.message);  
  55.                 dbus_error_free (&dberr);  
  56.                 return  EXIT_FAILURE;  
  57.         }  
  58.   
  59.         if  (!dbus_connection_add_filter (dbconn, filter_func, NULL, NULL))  
  60.                 return  EXIT_FAILURE;  
  61.   
  62.         dbus_bus_add_match (dbconn,  
  63.                             "type='signal',interface='com.wiley.test'" ,  
  64.                             &dberr);  
  65.   
  66.         if  (dbus_error_is_set (&dberr)) {  
  67.                 fprintf (stderr, "Could not match: %s" , dberr.message);  
  68.                 dbus_error_free (&dberr);  
  69.                 return  EXIT_FAILURE;  
  70.         }  
  71.   
  72.   
  73.         while  (dbus_connection_read_write_dispatch (dbconn, -1))  
  74.                 ; /* empty loop body */   
  75.   
  76.   
  77.         return  EXIT_SUCCESS;  
  78. }  

 爲了確保正確地接受到信號,我們必須確認擁有com.wiley.test命名空間:

  dbus_bus_request_name (dbconn, "com.wiley.test",DBUS_NAME_FLAG_REPLACE_EXISTING, &dberr);

 

   註冊過濾函數:

C代碼
  1. dbus_bool_t dbus_connection_add_filter      (   DBusConnection *     connection,  
  2.         DBusHandleMessageFunction   function,  
  3.         void  *      user_data,  
  4.         DBusFreeFunction    free_data_function     
  5.     )             
  6.        // connection    the connection   
  7.     // function     function to handle messages   
  8.     // user_data    user data to pass to the function   
  9.     // free_data_function   function to use for freeing user data    
  10.   
  11. //Adds a message filter.    
  12.   
  13.   if  (!dbus_connection_add_filter (dbconn, filter_func, NULL, NULL))  
  14.                 return  EXIT_FAILURE;  

     確保信號不會被忽略,因爲通過總線發送的信號有很多,並非所有的應用程序都對它們感興趣,所以默認情況下,信號將被忽略以阻止“信號氾濫”。

C代碼
  1. dbus_bus_add_match (dbconn,  
  2.                      "type='signal',interface='com.wiley.test'" ,  
  3.                      &dberr);  
  4.   
  5.  if  (dbus_error_is_set (&dberr)) {  
  6.          fprintf (stderr, "Could not match: %s" , dberr.message);  
  7.          dbus_error_free (&dberr);  
  8.          return  EXIT_FAILURE;  
  9.  }  

     一直監聽的代碼:

C代碼
  1. dbus_bool_t dbus_connection_read_write_dispatch     (   DBusConnection *     connection,  
  2.         int      timeout_milliseconds       
  3.     )             
  4.   
  5. //This function is intended for use with applications that don't want to //write a main loop and deal with DBusWatch and DBusTimeout.   
  6.   
  7. // An example usage would be:   
  8.   
  9.    while  (dbus_connection_read_write_dispatch (connection, -1))  
  10.      ; // empty loop body   

 過濾函數的實現:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章