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);
}
dbus-client.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);
}
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等等