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