16.2.2 D-Bus的用例

时间:2022-05-22 16:12:16

16.2.2  D-Bus的用例

在使用GNOME桌面环境的Linux系统中,通常用GLib库提供的函数来管理总线。在测试下列用例前,首先需要安装GTK+开发包(见22.3节)并配置编译环境。该用例一共包含两个程序文件,每个程序文件需单独编译成为可执行文件。

1.消息发送程序

dbus-ding-send.c”程序每秒通过会话总线发送一个参数为字符串Ding!的信号。该程序的源代码如下:

 

#include <glib.h>                                // 包含glib

#include <dbus/dbus-glib.h>                        // 包含glib库中D-Bus管理库

#include <stdio.h>

static gboolean send_ding(DBusConnection *bus);// 定义发送消息函数的原型

int main ()

{

   GMainLoop *loop;                              // 定义一个事件循环对象的指针

   DBusConnection *bus;                            // 定义总线连接对象的指针

   DBusError error;                              // 定义D-Bus错误消息对象

   loop = g_main_loop_new(NULL, FALSE);            // 创建新事件循环对象

   dbus_error_init (&error);                    // 将错误消息对象连接到D-Bus

                                                // 错误消息对象

   bus = dbus_bus_get(DBUS_BUS_SESSION, &error);// 连接到总线

   if (!bus) {                                // 判断是否连接错误

g_warning("连接到D-Bus失败: %s", error.message);

                                       // 使用GLib输出错误警告信息

      dbus_error_free(&error);              // 清除错误消息

      return 1;

   }

   dbus_connection_setup_with_g_main(bus, NULL);

                                            // 将总线设为接收GLib事件循环

   g_timeout_add(1000, (GSourceFunc)send_ding, bus);

                                    // 每隔1000ms调用一次send_ding()函数

                                            // 将总线指针作为参数

   g_main_loop_run(loop);                    // 启动事件循环

   return 0;

}

static gboolean send_ding(DBusConnection *bus)    // 定义发送消息函数的细节

{

   DBusMessage *message;                        // 创建消息对象指针

   message = dbus_message_new_signal("/com/burtonini/dbus/ding",

                                       "com.burtonini.dbus.Signal",

                                       "ding");        // 创建消息对象并标识路径

   dbus_message_append_args(message,

                            DBUS_TYPE_STRING, "ding!",

                            DBUS_TYPE_INVALID);        // 将字符串Ding!定义为消息

   dbus_connection_send(bus, message, NULL);    // 发送该消息

   dbus_message_unref(message);                    // 释放消息对象

   g_print("ding!/n");                            // 该函数等同与标准输入输出                                                      // 库的printf()

   return TRUE;

}

 

main()函数创建一个GLib事件循环,获得会话总线的一个连接,并将D-Bus事件处理集成到GLib事件循环之中。然后它创建了一个名为send_ding()函数作为间隔为一秒的计时器,并启动事件循环。send_ding()函数构造一个来自于对象路径“/com/burtonini/dbus/ding”和接口“com.burtonini.dbus.Signal”的新的Ding信号。然后,字符串Ding!作为参数添加到信号中并通过总线发送。在标准输出中会打印一条消息以让用户知道发送了一个信号。

2.消息接收程序

dbus-ding-listen.c程序通过会话总线接收dbus-ding-send.c程序发送到消息。该程序的源代码如下:

 

#include <glib.h>                                // 包含glib

#include <dbus/dbus-glib.h>                        // 包含glib库中D-Bus管理库

static DBusHandlerResult signal_filter        // 定义接收消息函数的原型

      (DBusConnection *connection, DBusMessage *message, void *user_data);

int main()

{

   GMainLoop *loop;                              // 定义一个事件循环对象的指针

   DBusConnection *bus;                            // 定义总线连接对象的指针

   DBusError error;                              // 定义D-Bus错误消息对象

   loop = g_main_loop_new(NULL, FALSE);            // 创建新事件循环对象

   dbus_error_init(&error);                      // 将错误消息对象连接到D-Bus

                                                  // 错误消息对象

   bus = dbus_bus_get(DBUS_BUS_SESSION, &error);    // 连接到总线

   if (!bus) {                                // 判断是否连接错误

g_warning("连接到D-Bus失败: %s", error.message);

                                       // 使用GLib输出错误警告信息

      dbus_error_free(&error);              // 清除错误消息

      return 1;

  }

   dbus_connection_setup_with_g_main(bus, NULL);   

                                            // 将总线设为接收GLib事件循环

   dbus_bus_add_match(bus, "type='signal',interface='com.burtonini.dbus.Signal'");    // 定义匹配器

   dbus_connection_add_filter(bus, signal_filter, loop, NULL);

                                            // 调用函数接收消息

   g_main_loop_run(loop);                    // 启动事件循环

   return 0;

}

static DBusHandlerResult                    // 定义接收消息函数的细节

signal_filter (DBusConnection *connection, DBusMessage *message, void *user_data)

{

   GMainLoop *loop = user_data;                // 定义事件循环对象的指针,并与主函                                         // 数中的同步

   if (dbus_message_is_signal               // 接收连接成功消息,判断是否连接

                                            // 失败

        (message, DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, "Disconnected")) {

      g_main_loop_quit (loop);             // 退出主循环

      return DBUS_HANDLER_RESULT_HANDLED;

   }

   if (dbus_message_is_signal(message, "com.burtonini.dbus.Signal",

   "Ping")) {

                                            // 指定消息对象路径,判断是否成功

      DBusError error;                      // 定义错误对象

      char *s;

dbus_error_init(&error);              // 将错误消息对象连接到D-Bus错误

                                       // 消息对象

      if (dbus_message_get_args                // 接收消息,并判断是否有错误

         (message, &error, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID)) {

         g_print("接收到的消息是: %s/n", s);    // 输出接收到的消息

         dbus_free (s);                        // 清除该消息

      }

      else {                                   // 有错误时执行下列语句

         g_print("消息已收到,但有错误提示: %s/n", error.message);

         dbus_error_free (&error);

      }

      return DBUS_HANDLER_RESULT_HANDLED;

   }

   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;

}

 

该程序侦听dbus-ping-send.c程序正在发出的信号。main()函数和前面一样启动,创建一个到总线的连接。然后它声明愿意在使用com.burtonini.dbus.Signal接口的信号被发送时得到通知,将signal_filter()函数设置为通知函数,然后进入事件循环。当满足匹配的消息被发送时,signal_func()函数会被调用。

如果需要确定在接收消息时如何处理,可通过检测消息头实现。若收到的消息为总线断开信号,则主事件循环将被终止,因为监听的总线已经不存在了。若收到其他的消息,首先将收到的消息与期待的消息进行比较,两者相同则输出其中参数,并退出程序。两者不相同则告知总线并没有处理该消息,这样消息会继续保留在总线*别的程序处理。