dbus有点类似Web Service,比如都是通过xml来规范接口模板
不同之处是WS是基于http协议的,跨主机调用。而dbus是在本地主机调用
使用WS的典型案例是onvif协议,因为以前有维护过onvif开发,所以对此有些了解
下面主要内容是:怎么用dbus创建一个提供Method的服务,并通过客户端调用这个Method
onvif是通过gsoap 把wsdl文件转化成c头文件
而dbus是通过提供的工具把xml文件转化成c头文件
下面有个xml文件 myxxx.xml
<?xml version="1.0" encoding="UTF-8" ?> <node name="/"> <interface name="org1.mydbus1.Test1.Basic1"> <method name="Add1"> <arg name="arg0" type="i"/> <arg name="arg1" type="i"/> <arg name="ret" type="i" direction="out"/> </method> <method name="Min2"> <arg name="arg0" type="i"/> <arg name="arg1" type="i"/> <arg name="ret" type="i" direction="out"/> </method> </interface> <interface name="org2.mydbus2.Test2.Basic2"> <method name="Mut3"> <arg name="arg0" type="i"/> <arg name="arg1" type="i"/> <arg name="ret" type="i" direction="out"/> </method> <method name="Dev4"> <arg name="arg0" type="i"/> <arg name="arg1" type="i"/> <arg name="ret" type="i" direction="out"/> </method> </interface> <interface name="org3.mydbus3.Test3.Basic3"> <method name="Add5"> <arg name="arg0" type="i"/> <arg name="arg1" type="i"/> <arg name="arg2" type="i"/> <arg name="ret" type="i" direction="out"/> </method> <method name="dia"> <arg name="arg0" type="s"/> <arg name="ret" type="s" direction="out"/> </method> </interface> </node>
通过dbus-binding-tool转换成c头文件
(apt-get install libdbus-glib-1-dev)
dbus-binding-tool --prefix=mydbus --mode=glib-server --output=myxxx.h myxxx.xml
转换后的myxxx.h内容如下
/* Generated by dbus-binding-tool; do not edit! */ #ifndef __dbus_glib_marshal_mydbus_MARSHAL_H__ #define __dbus_glib_marshal_mydbus_MARSHAL_H__ #include <glib-object.h> G_BEGIN_DECLS #ifdef G_ENABLE_DEBUG #define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) #define g_marshal_value_peek_char(v) g_value_get_schar (v) #define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) #define g_marshal_value_peek_int(v) g_value_get_int (v) #define g_marshal_value_peek_uint(v) g_value_get_uint (v) #define g_marshal_value_peek_long(v) g_value_get_long (v) #define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) #define g_marshal_value_peek_int64(v) g_value_get_int64 (v) #define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) #define g_marshal_value_peek_enum(v) g_value_get_enum (v) #define g_marshal_value_peek_flags(v) g_value_get_flags (v) #define g_marshal_value_peek_float(v) g_value_get_float (v) #define g_marshal_value_peek_double(v) g_value_get_double (v) #define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) #define g_marshal_value_peek_param(v) g_value_get_param (v) #define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) #define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) #define g_marshal_value_peek_object(v) g_value_get_object (v) #define g_marshal_value_peek_variant(v) g_value_get_variant (v) #else /* !G_ENABLE_DEBUG */ /* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. * Do not access GValues directly in your code. Instead, use the * g_value_get_*() functions */ #define g_marshal_value_peek_boolean(v) (v)->data[0].v_int #define g_marshal_value_peek_char(v) (v)->data[0].v_int #define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint #define g_marshal_value_peek_int(v) (v)->data[0].v_int #define g_marshal_value_peek_uint(v) (v)->data[0].v_uint #define g_marshal_value_peek_long(v) (v)->data[0].v_long #define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong #define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 #define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 #define g_marshal_value_peek_enum(v) (v)->data[0].v_long #define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong #define g_marshal_value_peek_float(v) (v)->data[0].v_float #define g_marshal_value_peek_double(v) (v)->data[0].v_double #define g_marshal_value_peek_string(v) (v)->data[0].v_pointer #define g_marshal_value_peek_param(v) (v)->data[0].v_pointer #define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer #define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer #define g_marshal_value_peek_object(v) (v)->data[0].v_pointer #define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer #endif /* !G_ENABLE_DEBUG */ /* BOOLEAN:STRING,POINTER,POINTER */ extern void dbus_glib_marshal_mydbus_BOOLEAN__STRING_POINTER_POINTER (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); void dbus_glib_marshal_mydbus_BOOLEAN__STRING_POINTER_POINTER (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef gboolean (*GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER) (gpointer data1, gpointer arg_1, gpointer arg_2, gpointer arg_3, gpointer data2); register GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; gboolean v_return; g_return_if_fail (return_value != NULL); g_return_if_fail (n_param_values == 4); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER) (marshal_data ? marshal_data : cc->callback); v_return = callback (data1, g_marshal_value_peek_string (param_values + 1), g_marshal_value_peek_pointer (param_values + 2), g_marshal_value_peek_pointer (param_values + 3), data2); g_value_set_boolean (return_value, v_return); } /* BOOLEAN:INT,INT,POINTER,POINTER */ extern void dbus_glib_marshal_mydbus_BOOLEAN__INT_INT_POINTER_POINTER (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); void dbus_glib_marshal_mydbus_BOOLEAN__INT_INT_POINTER_POINTER (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef gboolean (*GMarshalFunc_BOOLEAN__INT_INT_POINTER_POINTER) (gpointer data1, gint arg_1, gint arg_2, gpointer arg_3, gpointer arg_4, gpointer data2); register GMarshalFunc_BOOLEAN__INT_INT_POINTER_POINTER callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; gboolean v_return; g_return_if_fail (return_value != NULL); g_return_if_fail (n_param_values == 5); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_BOOLEAN__INT_INT_POINTER_POINTER) (marshal_data ? marshal_data : cc->callback); v_return = callback (data1, g_marshal_value_peek_int (param_values + 1), g_marshal_value_peek_int (param_values + 2), g_marshal_value_peek_pointer (param_values + 3), g_marshal_value_peek_pointer (param_values + 4), data2); g_value_set_boolean (return_value, v_return); } /* BOOLEAN:INT,INT,INT,POINTER,POINTER */ extern void dbus_glib_marshal_mydbus_BOOLEAN__INT_INT_INT_POINTER_POINTER (GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data); void dbus_glib_marshal_mydbus_BOOLEAN__INT_INT_INT_POINTER_POINTER (GClosure *closure, GValue *return_value G_GNUC_UNUSED, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { typedef gboolean (*GMarshalFunc_BOOLEAN__INT_INT_INT_POINTER_POINTER) (gpointer data1, gint arg_1, gint arg_2, gint arg_3, gpointer arg_4, gpointer arg_5, gpointer data2); register GMarshalFunc_BOOLEAN__INT_INT_INT_POINTER_POINTER callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; gboolean v_return; g_return_if_fail (return_value != NULL); g_return_if_fail (n_param_values == 6); if (G_CCLOSURE_SWAP_DATA (closure)) { data1 = closure->data; data2 = g_value_peek_pointer (param_values + 0); } else { data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } callback = (GMarshalFunc_BOOLEAN__INT_INT_INT_POINTER_POINTER) (marshal_data ? marshal_data : cc->callback); v_return = callback (data1, g_marshal_value_peek_int (param_values + 1), g_marshal_value_peek_int (param_values + 2), g_marshal_value_peek_int (param_values + 3), g_marshal_value_peek_pointer (param_values + 4), g_marshal_value_peek_pointer (param_values + 5), data2); g_value_set_boolean (return_value, v_return); } G_END_DECLS #endif /* __dbus_glib_marshal_mydbus_MARSHAL_H__ */ #include <dbus/dbus-glib.h> static const DBusGMethodInfo dbus_glib_mydbus_methods[] = { { (GCallback) mydbus_add1, dbus_glib_marshal_mydbus_BOOLEAN__INT_INT_POINTER_POINTER, 0 }, { (GCallback) mydbus_min2, dbus_glib_marshal_mydbus_BOOLEAN__INT_INT_POINTER_POINTER, 66 }, { (GCallback) mydbus_mut3, dbus_glib_marshal_mydbus_BOOLEAN__INT_INT_POINTER_POINTER, 132 }, { (GCallback) mydbus_dev4, dbus_glib_marshal_mydbus_BOOLEAN__INT_INT_POINTER_POINTER, 198 }, { (GCallback) mydbus_add5, dbus_glib_marshal_mydbus_BOOLEAN__INT_INT_INT_POINTER_POINTER, 264 }, { (GCallback) mydbus_dia, dbus_glib_marshal_mydbus_BOOLEAN__STRING_POINTER_POINTER, 339 }, }; const DBusGObjectInfo dbus_glib_mydbus_object_info = { 1, dbus_glib_mydbus_methods, 6, "org1.mydbus1.Test1.Basic1\0Add1\0S\0arg0\0I\0i\0arg1\0I\0i\0ret\0O\0F\0N\0i\0\0org1.mydbus1.Test1.Basic1\0Min2\0S\0arg0\0I\0i\0arg1\0I\0i\0ret\0O\0F\0N\0i\0\0org2.mydbus2.Test2.Basic2\0Mut3\0S\0arg0\0I\0i\0arg1\0I\0i\0ret\0O\0F\0N\0i\0\0org2.mydbus2.Test2.Basic2\0Dev4\0S\0arg0\0I\0i\0arg1\0I\0i\0ret\0O\0F\0N\0i\0\0org3.mydbus3.Test3.Basic3\0Add5\0S\0arg0\0I\0i\0arg1\0I\0i\0arg2\0I\0i\0ret\0O\0F\0N\0i\0\0org3.mydbus3.Test3.Basic3\0dia\0S\0arg0\0I\0s\0ret\0O\0F\0N\0s\0\0\0", "\0", "\0" };
接下来编写dbus-server.c
#include <dbus/dbus-glib.h> #include <stdio.h> #include <stdlib.h> static void lose (const char *fmt, ...) G_GNUC_NORETURN G_GNUC_PRINTF (1, 2); static void lose_gerror (const char *prefix, GError *error) G_GNUC_NORETURN; static void lose (const char *str, ...) { va_list args; va_start (args, str); vfprintf (stderr, str, args); fputc ('\n', stderr); va_end (args); exit (1); } static void lose_gerror (const char *prefix, GError *error) { lose ("%s: %s", prefix, error->message); } typedef struct TestObj { GObject parent; }TestObj; typedef struct TestObjClass { GObjectClass parent; }TestObjClass; G_DEFINE_TYPE(TestObj, mydbus, G_TYPE_OBJECT); GType mydbus_get_type (void); #define MYDBUS_TYPE_OBJECT (mydbus_get_type ()) //#define TEST_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), MYDBUS_TYPE_OBJECT, TestObj)) //#define TEST_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MYDBUS_TYPE_OBJECT, TestObjClass)) //#define TEST_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), MYDBUS_TYPE_OBJECT)) //#define TEST_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MYDBUS_TYPE_OBJECT)) //#define TEST_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MYDBUS_TYPE_OBJECT, TestObjClass)) gboolean mydbus_add1 (TestObj *obj, int num1, int num2, int *sum, GError **error); gboolean mydbus_min2 (TestObj *obj, int num1, int num2, int *sum, GError **error); gboolean mydbus_mut3 (TestObj *obj, int num1, int num2, int *sum, GError **error); gboolean mydbus_dev4 (TestObj *obj, int num1, int num2, int *sum, GError **error); gboolean mydbus_add5 (TestObj *obj, int num1, int num2, int num3, int *sum, GError **error); gboolean mydbus_dia (TestObj *obj, char *instr, char **outstr, GError **errore); #include "myxxx.h" static void mydbus_init (TestObj *obj) { } static void mydbus_class_init (TestObjClass *klass) { } gboolean mydbus_add1 (TestObj *obj, int num1, int num2, int *sum, GError **error) { *sum = num1 + num2; return TRUE; } gboolean mydbus_min2 (TestObj *obj, int num1, int num2, int *sum, GError **error) { *sum = num1 - num2; return TRUE; } gboolean mydbus_mut3 (TestObj *obj, int num1, int num2, int *sum, GError **error) { *sum = num1 * num2; return TRUE; } gboolean mydbus_dev4 (TestObj *obj, int num1, int num2, int *sum, GError **error) { if(!num2) return FALSE; *sum = num1 / num2; return TRUE; } gboolean mydbus_add5 (TestObj *obj, int num1, int num2, int num3, int *sum, GError **error) { *sum = num1 + num2 + num3; return TRUE; } gboolean mydbus_dia (TestObj *obj, char *in, char **out, GError **error) { /* free by caller */ *out = (char *)malloc(sizeof(char) * 1024); snprintf(*out, 1024, "%s", "this is server!"); return TRUE; } int main (int argc, char **argv) { DBusGConnection *bus; DBusGProxy *bus_proxy; GError *error = NULL; TestObj *obj; GMainLoop *mainloop; guint request_name_result; g_type_init (); { GLogLevelFlags fatal_mask; fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK); fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL; g_log_set_always_fatal (fatal_mask); } dbus_g_object_type_install_info (MYDBUS_TYPE_OBJECT, &dbus_glib_mydbus_object_info); mainloop = g_main_loop_new (NULL, FALSE); bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (!bus) lose_gerror ("Couldn't connect to session bus", error); bus_proxy = dbus_g_proxy_new_for_name (bus, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus"); if (!dbus_g_proxy_call (bus_proxy, "RequestName", &error, G_TYPE_STRING, "xyz.aaaaaaaa.xxxx", G_TYPE_UINT, 0, G_TYPE_INVALID, G_TYPE_UINT, &request_name_result, G_TYPE_INVALID)) lose_gerror ("Failed to acquire xyz.aaaaaaaa.xxxx", error); obj = g_object_new (MYDBUS_TYPE_OBJECT, NULL); dbus_g_connection_register_g_object (bus, "/MYDBUS", G_OBJECT (obj)); printf ("service running\n"); g_main_loop_run (mainloop); exit (0); }
#include <dbus/dbus-glib.h> #include <stdio.h> #include <stdlib.h> static void lose (const char *fmt, ...) G_GNUC_NORETURN G_GNUC_PRINTF (1, 2); static void lose_gerror (const char *prefix, GError *error) G_GNUC_NORETURN; static void lose (const char *str, ...) { va_list args; va_start (args, str); vfprintf (stderr, str, args); fputc ('\n', stderr); va_end (args); exit (1); } static void lose_gerror (const char *prefix, GError *error) { lose ("%s: %s", prefix, error->message); } static void print_hash_value (gpointer key, gpointer val, gpointer data) { printf ("%s -> %s\n", (char *) key, (char *) val); } int main (int argc, char **argv) { DBusGConnection *bus; DBusGProxy *remote_object; DBusGProxy *remote_object_str; DBusGProxy *remote_object_introspectable; GError *error = NULL; char *introspect_data; char *outstr; guint i; gint sum; g_type_init (); { GLogLevelFlags fatal_mask; fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK); fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL; g_log_set_always_fatal (fatal_mask); } bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (!bus) lose_gerror ("Couldn't connect to session bus", error); /* call Method add1 */ remote_object = dbus_g_proxy_new_for_name (bus, "xyz.aaaaaaaa.xxxx", /* BUS name */ "/MYDBUS", /* Object name */ "org1.mydbus1.Test1.Basic1"); /* Interface name */ if (!dbus_g_proxy_call (remote_object, "Add1", &error, /* Method name */ G_TYPE_INT, 1, G_TYPE_INT, 2, G_TYPE_INVALID, G_TYPE_INT, &sum, G_TYPE_INVALID)) lose_gerror ("Failed to call Add1", error); printf("sum is: %d\n", sum); /* call Method dia */ remote_object_str = dbus_g_proxy_new_for_name (bus, "xyz.aaaaaaaa.xxxx", /* BUS name */ "/MYDBUS", /* Object name */ "org3.mydbus3.Test3.Basic3"); /* Interface name */ if (!dbus_g_proxy_call (remote_object_str, "dia", &error, /* Method name */ G_TYPE_STRING, "Hello World!", G_TYPE_INVALID, G_TYPE_STRING, &outstr, G_TYPE_INVALID)) lose_gerror ("Failed to call dia", error); printf("outstr is: %s\n", outstr); g_free (outstr); /* call Method Introspect */ remote_object_introspectable = dbus_g_proxy_new_for_name (bus, "xyz.aaaaaaaa.xxxx", /* BUS name */ "/MYDBUS", /* Object name */ "org.freedesktop.DBus.Introspectable"); /* Interface name */ if (!dbus_g_proxy_call (remote_object_introspectable, "Introspect", &error, /* Method name */ G_TYPE_INVALID, G_TYPE_STRING, &introspect_data, G_TYPE_INVALID)) lose_gerror ("Failed to complete Introspect", error); printf ("%s", introspect_data); g_free (introspect_data); g_object_unref (G_OBJECT (remote_object_introspectable)); g_object_unref (G_OBJECT (remote_object)); g_object_unref (G_OBJECT (remote_object_str)); return 0; }编译dbus-server.c dbus-client.c
gcc -o dbusser -g dbus-server.c `pkg-config --cflags --libs /usr/lib/x86_64-linux-gnu/pkgconfig/dbus-glib-1.pc`
gcc -o dbuscli -g dbus-client.c `pkg-config --cflags --libs /usr/lib/x86_64-linux-gnu/pkgconfig/dbus-glib-1.pc`
运行dbusser
运行dbuscli, 结果如下
sum is: 3 outstr is: this is server! <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node> <interface name="org.freedesktop.DBus.Introspectable"> <method name="Introspect"> <arg name="data" direction="out" type="s"/> </method> </interface> <interface name="org.freedesktop.DBus.Properties"> <method name="Get"> <arg name="interface" direction="in" type="s"/> <arg name="propname" direction="in" type="s"/> <arg name="value" direction="out" type="v"/> </method> <method name="Set"> <arg name="interface" direction="in" type="s"/> <arg name="propname" direction="in" type="s"/> <arg name="value" direction="in" type="v"/> </method> <method name="GetAll"> <arg name="interface" direction="in" type="s"/> <arg name="props" direction="out" type="a{sv}"/> </method> </interface> <interface name="org3.mydbus3.Test3.Basic3"> <method name="dia"> <arg name="arg0" type="s" direction="in"/> <arg name="ret" type="s" direction="out"/> </method> <method name="Add5"> <arg name="arg0" type="i" direction="in"/> <arg name="arg1" type="i" direction="in"/> <arg name="arg2" type="i" direction="in"/> <arg name="ret" type="i" direction="out"/> </method> </interface> <interface name="org1.mydbus1.Test1.Basic1"> <method name="Min2"> <arg name="arg0" type="i" direction="in"/> <arg name="arg1" type="i" direction="in"/> <arg name="ret" type="i" direction="out"/> </method> <method name="Add1"> <arg name="arg0" type="i" direction="in"/> <arg name="arg1" type="i" direction="in"/> <arg name="ret" type="i" direction="out"/> </method> </interface> <interface name="org2.mydbus2.Test2.Basic2"> <method name="Dev4"> <arg name="arg0" type="i" direction="in"/> <arg name="arg1" type="i" direction="in"/> <arg name="ret" type="i" direction="out"/> </method> <method name="Mut3"> <arg name="arg0" type="i" direction="in"/> <arg name="arg1" type="i" direction="in"/> <arg name="ret" type="i" direction="out"/> </method> </interface> </node>
学习之后的一点感想:
dbus的工具集没有gsoap的工具集好用,开发dbus server端时函数实现不方便
dbus还有signal类似的通信方式,不过也是基于xml的,就没有继续研究了
测试dbus有个d-feet工具可以用,还有dbus工具集提供的工具如dbus-monitor dbus-send等等