D-BUS 代码的示例。
dbus-ping-send.c 每秒通过会话总线发送一个参数为字符串“Ping!”的信号。我使用 Glib 来管理总线,以使得我不需要自己来处理总线的连接细节。
清单 1. dbus-ping-send.c
#include <glib.h>
#include <dbus/dbus-glib.h>
static gboolean send_ping (DBusConnection *bus);
int
main (int argc, char **argv)
{
GMainLoop *loop;
DBusConnection *bus;
DBusError error;
/* Create a new event loop to run in */
loop = g_main_loop_new (NULL, FALSE);
/* Get a connection to the session bus */
dbus_error_init (&error);
bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
if (!bus) {
g_warning ("Failed to connect to the D-BUS daemon: %s", error.message);
dbus_error_free (&error);
return 1;
}
/* Set up this connection to work in a GLib event loop */
dbus_connection_setup_with_g_main (bus, NULL);
/* Every second call send_ping() with the bus as an argument*/
g_timeout_add (1000, (GSourceFunc)send_ping, bus);
/* Start the event loop */
g_main_loop_run (loop);
return 0;
}
static gboolean
send_ping (DBusConnection *bus)
{
DBusMessage *message;
/* Create a new signal "Ping" on the "com.burtonini.dbus.Signal" interface,
* from the object "/com/burtonini/dbus/ping". */
message = dbus_message_new_signal ("/com/burtonini/dbus/ping",
"com.burtonini.dbus.Signal", "Ping");
/* Append the string "Ping!" to the signal */
dbus_message_append_args (message,
DBUS_TYPE_STRING, "Ping!",
DBUS_TYPE_INVALID);
/* Send the signal */
dbus_connection_send (bus, message, NULL);
/* Free the signal now we have finished with it */
dbus_message_unref (message);
/* Tell the user we send a signal */
g_print("Ping!/n");
/* Return TRUE to tell the event loop we want to be called again */
return TRUE;
}
main 函数创建一个 GLib 事件循环,获得会话总线的一个连接,并将 D-BUS 事件处理集成到 Glib 事件循环之中。然后它创建了一个名为 send_ping 间隔为一秒的计时器,并启动事件循环。
de>send_pingde> 构造一个来自于对象路径 /com/burtonini/dbus/ping 和接口 com.burtonini.dbus.Signal 的新的 Ping 信号。然后,字符串 “Ping!”作为参数添加到信号中并通过总线发送。在标准输出中会打印一条消息以让用户知道发送了一个信号。
当然,不应该向总线发送了信号而没有任何程序在侦听它们……于是我们需要:
清单 2. dbus-ping-listen.c
#include <glib.h>
#include <dbus/dbus-glib.h>
static DBusHandlerResult signal_filter
(DBusConnection *connection, DBusMessage *message, void *user_data);
int
main (int argc, char **argv)
{
GMainLoop *loop;
DBusConnection *bus;
DBusError error;
loop = g_main_loop_new (NULL, FALSE);
dbus_error_init (&error);
bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
if (!bus) {
g_warning ("Failed to connect to the D-BUS daemon: %s", error.message);
dbus_error_free (&error);
return 1;
}
dbus_connection_setup_with_g_main (bus, NULL);
/* listening to messages from all objects as no path is specified */
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)
{
/* User data is the event loop we are running in */
GMainLoop *loop = user_data;
/* A signal from the bus saying we are about to be disconnected */
if (dbus_message_is_signal
(message, DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, "Disconnected")) {
/* Tell the main loop to quit */
g_main_loop_quit (loop);
/* We have handled this message, don't pass it on */
return DBUS_HANDLER_RESULT_HANDLED;
}
/* A Ping signal on the com.burtonini.dbus.Signal interface */
else if (dbus_message_is_signal (message, "com.burtonini.dbus.Signal", "Ping")) {
DBusError error;
char *s;
dbus_error_init (&error);
if (dbus_message_get_args
(message, &error, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID)) {
g_print("Ping received: %s/n", s);
dbus_free (s);
} else {
g_print("Ping received, but error getting message: %s/n", error.message);
dbus_error_free (&error);
}
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
清单 3. Makefile
CC = gcc
CC=gcc
CFLAGS = `pkg-config --cflags --libs gtk+-2.0 dbus-1 dbus-glib-1` -g -Wall
DBUS = -I/usr/include/dbus-1.0/ -I/usr/lib/dbus-1.0/include/ -ldbus-1
dbus-send:dbus-ping-send.c
$(CC) $(CFLAGS) $(DBUS) -o $@ $<
make dbus-send
这个程序侦听 dbus-ping-send.c 正在发出的信号。 de>mainde> 函数和前面一样启动,创建一个到总线的连接。然后它声明愿意当具有 de>com.burtonini.dbus.Signalde> 接口的信号被发送时得到通知,将 de>signal_filterde> 设置为通知函数,然后进入事件循环。
当满足匹配的消息被发送时, de>signal_funcde> 会被调用。不过,它也将会收到来自总线本身的总线管理信号。要确定接收到消息时应该做些什么,仅仅需要检验消息头。如果消息是总线断开信号,则事件循环终 止,因为侦听一个不存在的总线是没有意义的。(告知总线信号已经处理)。然后,将到来的消息与期望的消息相比较,如果成功,则解出参数并输出。如果到来的 消息不是其中的任何一个,则告知总线没有处理那个消息。
网上有python的代码。其比 dbus-ping-listen.c 中相应的 de>C 代码de> 更简明,也更容易读懂。此外,有些地方需要做绑定的工作(当调用 de>bus.add_signal_receiverde> 时,用户必须传入一个接口和一个对象路径;否则会创建不正常的匹配器)。这是一个微不足道的缺陷,一旦这个缺陷被修正,就可以去服务和对象路径参数除,这将进一步提高代码的可读性。