天天看点

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. int  main ( int  argc,  char  *argv[])  
  5. {  
  6.         DBusError dberr;  
  7.         DBusConnection *dbconn;  
  8.         DBusMessage *dbmsg;  
  9.         char  *text;  
  10.         dbus_error_init (&dberr);  
  11.         dbconn = dbus_bus_get (DBUS_BUS_SESSION, &dberr);  //代表连接到会话总线,如果需要连接到   
  12.        //系统总线,简单把DBUS_BUS_SESSION替换为DBUS_BUS_SYSTEM即可。但是有麻烦,因为   
  13.      //系统总线对可以连接到它的用户有限制。可能需要提供一个.service文件指明能连接到某一个指定服务器的权限   
  14.         if  (dbus_error_is_set (&dberr)) {  
  15.                 fprintf (stderr, "getting session bus failed: %s/n" , dberr.message);  
  16.                 dbus_error_free (&dberr);  
  17.                 return  EXIT_FAILURE;  
  18.         }  
  19.         dbmsg = dbus_message_new_signal ("/com/wiley/test" ,  
  20.                                          "com.wiley.test" ,  
  21.                                          "TestSignal" );  
  22.         if  (dbmsg == NULL) {  
  23.                 fprintf (stderr, "Could not create a new signal/n" );  
  24.                 return  EXIT_FAILURE;  
  25.         }  
  26.         text = "Hello World" ;  
  27.         dbus_message_append_args (dbmsg, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID);  
  28.         dbus_connection_send (dbconn, dbmsg, NULL);  
  29.         printf ("Sending signal to D-Bus/n" );  
  30.         dbus_message_unref (dbmsg);  
  31.         dbus_connection_unref (dbconn);  
  32.         return  EXIT_SUCCESS;  
  33. }  
#include <dbus/dbus.h>  //要使用dbus则必须包含此文件
#include <stdlib.h>
#include <stdio.h>

/*
cc $(pkg-config --cflags --libs dbus-glib-1) -o dbus-send-hello dbus-send-hello.c && ./dbus-send-hello
*/

int main (int argc, char *argv[])
{
        DBusError dberr;
        DBusConnection *dbconn;
        DBusMessage *dbmsg;
        char *text;

        dbus_error_init (&dberr);
        dbconn = dbus_bus_get (DBUS_BUS_SESSION, &dberr);  //代表连接到会话总线,如果需要连接到
       //系统总线,简单把DBUS_BUS_SESSION替换为DBUS_BUS_SYSTEM即可。但是有麻烦,因为
     //系统总线对可以连接到它的用户有限制。可能需要提供一个.service文件指明能连接到某一个指定服务器的权限
        if (dbus_error_is_set (&dberr)) {
                fprintf (stderr, "getting session bus failed: %s/n", dberr.message);
                dbus_error_free (&dberr);
                return EXIT_FAILURE;
        }

        dbmsg = dbus_message_new_signal ("/com/wiley/test",
                                         "com.wiley.test",
                                         "TestSignal");
/* 函数原型是
DBusMessage* dbus_message_new_signal (const char *path,  
                      const char *interface,  
                     const char *name) */

        if (dbmsg == NULL) {
                fprintf (stderr, "Could not create a new signal/n");
                return EXIT_FAILURE;
        }

        text = "Hello World";
        dbus_message_append_args (dbmsg, DBUS_TYPE_STRING, &text, DBUS_TYPE_INVALID);

        dbus_connection_send (dbconn, dbmsg, NULL);
        printf ("Sending signal to D-Bus/n");

        dbus_message_unref (dbmsg);

        dbus_connection_unref (dbconn);

        return EXIT_SUCCESS;
}
      

  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);  
dbus_int32_t v_INT32 = 42;
 const char *v_STRING = "Hello World";
 dbus_message_append_args (message,
                           DBUS_TYPE_INT32, &v_INT32,
                           DBUS_TYPE_STRING, &v_STRING,
                           DBUS_TYPE_INVALID);
const dbus_int32_t array[] = { 1, 2, 3 };
 const dbus_int32_t *v_ARRAY = array;
 dbus_message_append_args (message,
                           DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, &v_ARRAY, 3,
                           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_bool_t dbus_connection_send  	(  	DBusConnection *   	 connection,
		DBusMessage *  	message,
		dbus_uint32_t *  	serial	 
	) 	
       connection 	the connection.
	message 	the message to write.
	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. static  DBusHandlerResult  
  5. filter_func (DBusConnection *connection,  
  6.              DBusMessage *message,  
  7.              void  *user_data)  
  8. {  
  9.         dbus_bool_t handled = FALSE;  
  10.         char  *signal_text = NULL;  
  11.         if  (dbus_message_is_signal (message,  "com.wiley.test" ,  "TestSignal" )) {  
  12.                 DBusError dberr;  
  13.                 dbus_error_init (&dberr);  
  14.                 dbus_message_get_args (message, &dberr, DBUS_TYPE_STRING, &signal_text, DBUS_TYPE_INVALID);  
  15.                 if  (dbus_error_is_set (&dberr)) {  
  16.                         fprintf (stderr, "Error getting message args: %s" , dberr.message);  
  17.                         dbus_error_free (&dberr);  
  18.                 } else  {  
  19.                         DBusConnection *dbconn = (DBusConnection*) user_data;  
  20.                         printf ("Received TestSignal with value of: '%s'/n" , signal_text);  
  21.                         handled = TRUE;  
  22.                 }  
  23.         }  
  24.         return  (handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED);  
  25. }  
  26. int  main ( int  argc,  char  *argv[])  
  27. {  
  28.         DBusError dberr;  
  29.         DBusConnection *dbconn;  
  30.         dbus_error_init (&dberr);  
  31.         dbconn = dbus_bus_get (DBUS_BUS_SESSION, &dberr);  
  32.         if  (dbus_error_is_set (&dberr)) {  
  33.                 fprintf (stderr, "getting session bus failed: %s/n" , dberr.message);  
  34.                 dbus_error_free (&dberr);  
  35.                 return  EXIT_FAILURE;  
  36.         }  
  37.         dbus_bus_request_name (dbconn, "com.wiley.test" ,  
  38.                                DBUS_NAME_FLAG_REPLACE_EXISTING, &dberr);  
  39.         if  (dbus_error_is_set (&dberr)) {  
  40.                 fprintf (stderr, "requesting name failed: %s/n" , dberr.message);  
  41.                 dbus_error_free (&dberr);  
  42.                 return  EXIT_FAILURE;  
  43.         }  
  44.         if  (!dbus_connection_add_filter (dbconn, filter_func, NULL, NULL))  
  45.                 return  EXIT_FAILURE;  
  46.         dbus_bus_add_match (dbconn,  
  47.                             "type='signal',inter" ,  
  48.                             &dberr);  
  49.         if  (dbus_error_is_set (&dberr)) {  
  50.                 fprintf (stderr, "Could not match: %s" , dberr.message);  
  51.                 dbus_error_free (&dberr);  
  52.                 return  EXIT_FAILURE;  
  53.         }  
  54.         while  (dbus_connection_read_write_dispatch (dbconn, -1))  
  55.                 ;    
  56.         return  EXIT_SUCCESS;  
  57. }  
#include <dbus/dbus.h>
#include <stdlib.h>
#include <stdio.h>

/*
cc $(pkg-config --cflags --libs dbus-glib-1) -o dbus-get-hello dbus-get-hello.c && ./dbus-get-hello
*/

static DBusHandlerResult
filter_func (DBusConnection *connection,
             DBusMessage *message,
             void *user_data)
{
        dbus_bool_t handled = FALSE;
        char *signal_text = NULL;

        if (dbus_message_is_signal (message, "com.wiley.test", "TestSignal")) {
                DBusError dberr;

                dbus_error_init (&dberr);
                dbus_message_get_args (message, &dberr, DBUS_TYPE_STRING, &signal_text, DBUS_TYPE_INVALID);
                if (dbus_error_is_set (&dberr)) {
                        fprintf (stderr, "Error getting message args: %s", dberr.message);
                        dbus_error_free (&dberr);
                } else {
                        DBusConnection *dbconn = (DBusConnection*) user_data;

                        printf ("Received TestSignal with value of: '%s'/n", signal_text);

                        handled = TRUE;
                }
        }

        return (handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
}


int main (int argc, char *argv[])
{
        DBusError dberr;
        DBusConnection *dbconn;

        dbus_error_init (&dberr);
        dbconn = dbus_bus_get (DBUS_BUS_SESSION, &dberr);
        if (dbus_error_is_set (&dberr)) {
                fprintf (stderr, "getting session bus failed: %s/n", dberr.message);
                dbus_error_free (&dberr);
                return EXIT_FAILURE;
        }

        dbus_bus_request_name (dbconn, "com.wiley.test",
                               DBUS_NAME_FLAG_REPLACE_EXISTING, &dberr);
        if (dbus_error_is_set (&dberr)) {
                fprintf (stderr, "requesting name failed: %s/n", dberr.message);
                dbus_error_free (&dberr);
                return EXIT_FAILURE;
        }

        if (!dbus_connection_add_filter (dbconn, filter_func, NULL, NULL))
                return EXIT_FAILURE;

        dbus_bus_add_match (dbconn,
                            "type='signal',inter",
                            &dberr);

        if (dbus_error_is_set (&dberr)) {
                fprintf (stderr, "Could not match: %s", dberr.message);
                dbus_error_free (&dberr);
                return EXIT_FAILURE;
        }


        while (dbus_connection_read_write_dispatch (dbconn, -1))
                ; /* empty loop body */


        return EXIT_SUCCESS;
}      

 为了确保正确地接受到信号,我们必须确认拥有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. //Adds a message filter.    
  11.   if  (!dbus_connection_add_filter (dbconn, filter_func, NULL, NULL))  
  12.                 return  EXIT_FAILURE;  
dbus_bool_t dbus_connection_add_filter  	(  	DBusConnection *   	 connection,
		DBusHandleMessageFunction  	function,
		void *  	user_data,
		DBusFreeFunction  	free_data_function	 
	) 			
       // connection 	the connection
	// function 	function to handle messages
	// user_data 	user data to pass to the function
	// free_data_function 	function to use for freeing user data 

//Adds a message filter. 

  if (!dbus_connection_add_filter (dbconn, filter_func, NULL, NULL))
                return EXIT_FAILURE;      

     确保信号不会被忽略,因为通过总线发送的信号有很多,并非所有的应用程序都对它们感兴趣,所以默认情况下,信号将被忽略以阻止“信号泛滥”。

C代码

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

        if (dbus_error_is_set (&dberr)) {
                fprintf (stderr, "Could not match: %s", dberr.message);
                dbus_error_free (&dberr);
                return EXIT_FAILURE;
        }      

     一直监听的代码:

C代码

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

//This function is intended for use with applications that don't want to //write a main loop and deal with DBusWatch and DBusTimeout.

// An example usage would be:

   while (dbus_connection_read_write_dispatch (connection, -1))
     ; // empty loop body
      

 过滤函数的实现: