转发:http://www.emilmont.net/doku.php?id=c:d-bus
D-BUS
D-Bus is a message bus system, a simple way for applications to talk to one another. In addition to interprocess communication, D-Bus helps coordinate process lifecycle; it makes it simple and reliable to code a “single instance” application or daemon, and to launch applications and daemons on demand when their services are needed.
D-Bus supplies both a system daemon (for events such as “new hardware device added” or “printer queue changed”) and a per-user-login-session daemon (for general IPC needs among user applications).
On the D-Bus are defined only four message types:
-
Method call messages
-
Method return messages
-
Error messages (exception caused by invoking a method)
-
Signal messages
Each D-Bus message contains a signature of the contained data.
D-Bus Object
Every group of calls/signals published on the D-Bus are associated to an object abstraction.
Every object on the D-Bus has a path and an interface defined in an XML file:
service.xml
<?xml version="1.0" encoding="UTF-8" ?> <node name="/"> <interface name="org.example.TestService"> <method name="Method_1"> <arg name="data_a" type="s" direction = "in"/> <arg name="data_b" type="as" direction="out"/> </method> <signal name="Signal_1"/> </interface> </node>
The type of the arguments can be used by the D-Bus bindings to marshal and un-marshal the data.
The GLib bindings can generate, with the dbus-binding-tool, a “glue” header to be used with a GObject:
dbus-binding-tool --prefix=test_object --mode=glib-server service.xml > service-glue.h
-
–prefix is the name of the GObject that will implements the service method
The header and the object implementation follow always the same pattern:
test-object.h
#ifndef TEST_OBJECT_H_ #define TEST_OBJECT_H_ typedef struct TestObject_s { GObject parent; } TestObject; typedef struct TestObjectClass_s { GObjectClass parent; } TestObjectClass; #define TEST_TYPE_OBJECT (test_object_get_type()) #define TEST_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TEST_TYPE_OBJECT, TestObject)) #define TEST_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_OBJECT, TestObjectClass)) #define TEST_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TEST_TYPE_OBJECT)) #define TEST_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TEST_TYPE_OBJECT)) #define TEST_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_OBJECT, TestObjectClass)) extern GType test_object_get_type(void); gboolean method_1_implementation(...) ; #endif /*TEST_OBJECT_H_*/
test-object.c
#include <dbus/dbus-glib.h> #include <glib-object.h> #include "test-object.h" G_DEFINE_TYPE(TestObject, test_object, G_TYPE_OBJECT) static void test_object_init(TestObject *obj) { } /* Signals initialization */ static guint signal = 0; static void test_object_class_init(TestObjectClass *klass) { signal = g_signal_new ("Signal_1", G_OBJECT_CLASS_TYPE (klass), (G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED), 0, NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); } /* Method implementation */ gboolean method_1(...) { return TRUE; }
At initialization, the GObject has to be registered on the D-Bus:
Server
/* Object Initialization */ g_type_init(); dbus_g_object_type_install_info(SOME_TYPE_OBJECT, &dbus_glib_some_object_object_info); /* Main Loop initialization */ mainloop = g_main_loop_new(NULL, FALSE); /* D-Bus Connection */ bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error); if (!bus) g_error("Couldn't connect to session bus %s", error->message); bus_proxy = dbus_g_proxy_new_for_name (bus, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus"); /* Service registration to the D-Bus */ if (!dbus_g_proxy_call(bus_proxy, "RequestName", &error, G_TYPE_STRING, "org.example.TestService", G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &request_name_result, G_TYPE_INVALID)) g_error("Failed to acquire org.example.TestService: %s", error->message); /* Bounding of an instance of the object that implements the service on D-Bus */ obj = g_object_new(TEST_TYPE_OBJECT, NULL); dbus_g_connection_register_g_object(bus, "/TestObject", G_OBJECT (obj)); /* Main Loop */ g_main_loop_run(mainloop);
Client
/* GLib initing */ g_type_init(); mainloop = g_main_loop_new(NULL, FALSE); /* D-Bus Connection*/ bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error); if (!bus) fatal_gerror("Couldn't connect to session bus", error); /* Construction of a new proxy for the remote object */ remote_object = dbus_g_proxy_new_for_name(bus, "org.example.TestService", "/org/example/TestService/object", "org.designfu.TestService"); if (!remote_object) g_error("Failed to get name owner: %s", error->message); /* Remote object method call */ if (!dbus_g_proxy_call (remote_object, "HelloWorld", &error, G_TYPE_STRING, "Hello from example-client.c!", G_TYPE_INVALID, G_TYPE_STRV, &reply_list, G_TYPE_INVALID)) g_error("Failed to complete HelloWorld: %s", error->message); /* Connection to a remote object signal */ dbus_g_proxy_add_signal (remote_object, "HelloSignal", G_TYPE_STRING, G_TYPE_INVALID); dbus_g_proxy_connect_signal(remote_object, "HelloSignal", G_CALLBACK (hello_signal_handler), NULL, NULL); /* Main Loop */ g_main_loop_run(mainloop);