bluez 协议栈实现3 应用层的协议栈实现分析之dbus

由于bluez5用到了glib dbus等技术或库,先了解一下这两个

基本信息

D-Bus是针对桌面环境优化的IPC(interprocess communication )机制,用于进程间的通信或进程与内核的通信。最基本的D-Bus协议是一对一的通信协议。但在很多情况下,通信的一方是消息总线。消息总线是一个特殊的应用,它同时与多个应用通信,并在应用之间传递消息。下面我们会在实例中观察消息总线的作用。消息总线的角色有点类似与X系统中的窗口管理器,窗口管理器既是X客户,又负责管理窗口。

先用ubuntu下的d-feet来认识一下dbus



基本名词有
bus type:有两种类型的bus,system和session
bus name :一个Bus Name总是代表一个应用和消息总线的连接。比如org.fmddlmyy.Test
object path:比如org.fmddlmyy.Test总线下的/TestObj
interface: 比如/TestObj对象下的org.fmddlmyy.Test.Basic
method:比如org.fmddlmyy.Test.Basic接口下的Add方法
框架对给每个对象自动添加一个标准接口org.freedesktop.DBus.Introspectable,这个标准接口下有一个方法Introspect。调用Introspect方法可以返回所有接口的xml描述。


命令测试


linux下主要有如下命令来测试
dbus-send
dbus-monitor
另外还有一个python实现的gui界面 d-feet 

遍历dbus上的所有对象

root@ubuntu:/opt/ss/dteeth# dbus-send --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames
method return sender=org.freedesktop.DBus -> dest=:1.204 reply_serial=2
   array [
      string "org.freedesktop.DBus"
      string "org.freedesktop.Notifications"
      string "org.fmddlmyy.Test"
]

向某个对象发送消息
root@ubuntu:/opt/ss/dteeth# dbus-send --session --type=method_call --print-reply --dest=org.fmddlmyy.Test / org.freedesktop.DBus.Introspectable.Introspect
method return sender=:1.197 -> dest=:1.210 reply_serial=2
   string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
  <node name="TestObj"/>
</node>
"
root@ubuntu:/opt/ss/dteeth# dbus-send --session --type=method_call --print-reply --dest=org.fmddlmyy.Test/TestObj org.freedesktop.DBus.Introspectable.Introspect
method return sender=:1.197 -> dest=:1.211 reply_serial=2
   string "<!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="org.fmddlmyy.Test.Basic">
    <method name="Add">
      <arg name="arg0" type="i" direction="in"/>
      <arg name="arg1" type="i" direction="in"/>
      <arg name="ret" type="i" direction="out"/>
    </method>
  </interface>
</node>
"

root@ubuntu:/opt/ss/dteeth# dbus-send --session --type=method_call --print-reply --dest=org.fmddlmyy.Test /TestObj org.fmddlmyy.Test.Basic.Add int32:100 int32:999  
method return sender=:1.96 -> dest=:1.160 reply_serial=2
   int32 1099


Usage: dbus-send [--help] [--system | --session | --address=ADDRESS] [--dest=NAME] [--type=TYPE] [--print-reply=(literal)] [--reply-timeout=MSEC] <destination object path> <message name> [contents ...]

destination object path指的是object path
message name指的是 interface / method

imx6ul 上遍历所有消息
root@imx6ulevk:~# dbus-send --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames
method return sender=org.freedesktop.DBus -> dest=:1.29 reply_serial=2
   array [
      string "org.freedesktop.DBus"
      string ":1.3"
      string "org.freedesktop.Avahi"
      string ":1.0"
      string ":1.29"
      string "org.bluez"
      string ":1.1"
      string ":1.2"
      string "org.ofono"
   ]

如果出现如下error
Failed to open connection to session bus: Using X11 for dbus-daemon autolaunch was disabled at compile time, set your DBUS_SESSION_BUS_ADDRESS instead
执行如下命令来添加一个环境变量DBUS_SESSION_BUS_ADDRESS
export DBUS_SESSION_BUS_ADDRESS="unix:path=/var/run/dbus/system_bus_socket"

root@imx6ulevk:/mnt# dbus-send --session --type=method_call --print-reply --dest=org.bluez / org.freedesktop.DBus.Introspectable.Introspect

method return sender=:1.15 -> dest=:1.27 reply_serial=2
   string "
<!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="xml" type="s" direction="out"/>
        </method>
    </interface>
    <interface name="org.freedesktop.DBus.ObjectManager">
        <method name="GetManagedObjects">
            <arg name="objects" type="a{oa{sa{sv}}}" direction="out"/>
        </method>
        <signal name="InterfacesAdded">
            <arg name="object" type="o"/>
            <arg name="interfaces" type="a{sa{sv}}"/>
        </signal>
        <signal name="InterfacesRemoved">
            <arg name="object" type="o"/>
            <arg name="interfaces" type="as"/>
        </signal>
    </interface>
    <node name="org"/></node>"



root@imx6ulevk:/mnt# dbus-send --session --type=method_call --print-reply --dest=org.bluez /org org.freedesktop.DBus.Introspectable.Introspect


method return sender=:1.15 -> dest=:1.28 reply_serial=2
   string "
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
    <node name="bluez"/></node>
"


root@imx6ulevk:/mnt# dbus-send --session --type=method_call --print-reply --dest=org.bluez /org/bluez  org.freedesktop.DBus.Introspectable.Introspect


method return sender=:1.15 -> dest=:1.29 reply_serial=2
   string "
<!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="xml" type="s" direction="out"/>
        </method>
    </interface>
    <interface name="org.bluez.AgentManager1">
        <method name="RegisterAgent">
            <arg name="agent" type="o" direction="in"/>
            <arg name="capability" type="s" direction="in"/>
        </method>
        <method name="UnregisterAgent">
            <arg name="agent" type="o" direction="in"/>
        </method>
        <method name="RequestDefaultAgent">
            <arg name="agent" type="o" direction="in"/>
        </method>
    </interface>
    <interface name="org.bluez.ProfileManager1">
        <method name="RegisterProfile">
            <arg name="profile" type="o" direction="in"/>
            <arg name="UUID" type="s" direction="in"/>
            <arg name="options" type="a{sv}" direction="in"/>
        </method>
        <method name="UnregisterProfile">
            <arg name="profile" type="o" direction="in"/>
        </method>
    </interface>
    <node name="hci0"/></node>"

dbus-send --session --type=method_call --print-reply --dest=org.bluez /org/bluez/hci0  org.freedesktop.DBus.Introspectable.Introspect

method return sender=:1.15 -> dest=:1.36 reply_serial=2
   string "
<!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="xml" type="s" direction="out"/>
        </method>
    </interface>
    <interface name="org.bluez.Adapter1">
        <method name="StartDiscovery"></method>
        <method name="StopDiscovery"></method>
        <method name="RemoveDevice">
            <arg name="device" type="o" direction="in"/>
        </method>
        <property name="Address" type="s" access="read"></property>
        <property name="Name" type="s" access="read"></property>
        <property name="Alias" type="s" access="readwrite"></property>
        <property name="Class" type="u" access="read"></property>
        <property name="Powered" type="b" access="readwrite"></property>
        <property name="Discoverable" type="b" access="readwrite"></property>
        <property name="DiscoverableTimeout" type="u" access="readwrite"></property>
        <property name="Pairable" type="b" access="readwrite"></property>
        <property name="PairableTimeout" type="u" access="readwrite"></property>
        <property name="Discovering" type="b" access="read"></property>
        <property name="UUIDs" type="as" access="read"></property>
        <property name="Modalias" type="s" access="read"></property>
    </interface>
    <interface name="org.freedesktop.DBus.Properties">
        <method name="Get">
            <arg name="interface" type="s" direction="in"/>
            <arg name="name" type="s" direction="in"/>
            <arg name="value" type="v" direction="out"/>
        </method>
        <method name="Set">
            <arg name="interface" type="s" direction="in"/>
            <arg name="name" type="s" direction="in"/>
            <arg name="value" type="v" direction="in"/>
        </method>
        <method name="GetAll">
            <arg name="interface" type="s" direction="in"/>
            <arg name="properties" type="a{sv}" direction="out"/>
        </method>
        <signal name="PropertiesChanged">
            <arg name="interface" type="s"/>
            <arg name="changed_properties" type="a{sv}"/>
            <arg name="invalidated_properties" type="as"/>
        </signal>
    </interface>
    <interface name="org.bluez.Media1">
        <method name="RegisterEndpoint">
            <arg name="endpoint" type="o" direction="in"/>
            <arg name="properties" type="a{sv}" direction="in"/>
        </method>
        <method name="UnregisterEndpoint">
            <arg name="endpoint" type="o" direction="in"/>
        </method>
        <method name="RegisterPlayer">
            <arg name="player" type="o" direction="in"/>
            <arg name="properties" type="a{sv}" direction="in"/>
        </method>
        <method name="UnregisterPlayer">
            <arg name="player" type="o" direction="in"/>
        </method>
    </interface>
    <interface name="org.bluez.NetworkServer1">
        <method name="Register">
            <arg name="uuid" type="s" direction="in"/>
            <arg name="bridge" type="s" direction="in"/>
        </method>
        <method name="Unregister">
            <arg name="uuid" type="s" direction="in"/>
        </method>
    </interface>
    <node name="dev_00_1A_7D_DA_71_04"/>
    <node name="dev_00_1A_7D_DA_71_0D"/>
    <node name="dev_10_2A_27_34_19_D4"/>
    <node name="dev_58_71_33_33_71_7D"/>
    <node name="dev_68_A0_F6_B8_EB_09"/>
    <node name="dev_68_A0_F6_E3_99_CB"/>
    <node name="dev_F4_8E_92_78_83_70"/></node>"

dbus-send --session --type=method_call --print-reply --dest=org.bluez /org/bluez/hci0/dev_58_71_33_33_71_7D  org.freedesktop.DBus.Introspectable.Introspect

method return sender=:1.15 -> dest=:1.37 reply_serial=2
   string "
<!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="xml" type="s" direction="out"/>
        </method>
    </interface>
    <interface name="org.bluez.Device1">
        <method name="Disconnect"></method>
        <method name="Connect"></method>
        <method name="ConnectProfile">
            <arg name="UUID" type="s" direction="in"/>
        </method>
        <method name="DisconnectProfile">
            <arg name="UUID" type="s" direction="in"/>
        </method>
        <method name="Pair"></method>
        <method name="CancelPairing"></method>
        <property name="Address" type="s" access="read"></property>
        <property name="Name" type="s" access="read"></property>
        <property name="Alias" type="s" access="readwrite"></property>
        <property name="Class" type="u" access="read"></property>
        <property name="Appearance" type="q" access="read"></property>
        <property name="Icon" type="s" access="read"></property>
        <property name="Paired" type="b" access="read"></property>
        <property name="Trusted" type="b" access="readwrite"></property>
        <property name="Blocked" type="b" access="readwrite"></property>
        <property name="LegacyPairing" type="b" access="read"></property>
        <property name="RSSI" type="n" access="read"></property>
        <property name="Connected" type="b" access="read"></property>
        <property name="UUIDs" type="as" access="read"></property>
        <property name="Modalias" type="s" access="read"></property>
        <property name="Adapter" type="o" access="read"></property>
    </interface>
    <interface name="org.freedesktop.DBus.Properties">
        <method name="Get">
            <arg name="interface" type="s" direction="in"/>
            <arg name="name" type="s" direction="in"/>
            <arg name="value" type="v" direction="out"/>
        </method>
        <method name="Set">
            <arg name="interface" type="s" direction="in"/>
            <arg name="name" type="s" direction="in"/>
            <arg name="value" type="v" direction="in"/>
        </method>
        <method name="GetAll">
            <arg name="interface" type="s" direction="in"/>
            <arg name="properties" type="a{sv}" direction="out"/>
        </method>
        <signal name="PropertiesChanged">
            <arg name="interface" type="s"/>
            <arg name="changed_properties" type="a{sv}"/>
            <arg name="invalidated_properties" type="as"/>
        </signal>
    </interface>
    <interface name="org.bluez.Input1">
        <property name="ReconnectMode" type="s" access="read"></property>
    </interface>
</node>"






dbus-monitor
用于监视dbus上消息


c库代码

//example-service.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 TestObj;
typedef struct TestObjClass TestObjClass;

GType test_obj_get_type (void);

struct TestObj
{
GObject parent;
};

struct TestObjClass
{
GObjectClass parent;
};

#define TEST_TYPE_OBJECT              (test_obj_get_type ())
#define TEST_OBJECT(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), TEST_TYPE_OBJECT, TestObj))
#define TEST_OBJECT_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_OBJECT, TestObjClass))
#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, TestObjClass))

G_DEFINE_TYPE(TestObj, test_obj, G_TYPE_OBJECT)

gboolean test_obj_add (TestObj *obj, int num1, int num2, int *sum, GError **error);

#include "example-service-glue.h"

static void test_obj_init (TestObj *obj)
{
}

static void test_obj_class_init (TestObjClass *klass)
{
}

gboolean test_obj_add (TestObj *obj, int num1, int num2, int *sum, GError **error)
{
	*sum = num1 + num2;
	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 (TEST_TYPE_OBJECT, &dbus_glib_test_obj_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, "org.fmddlmyy.Test",
		  G_TYPE_UINT, 0,
		  G_TYPE_INVALID,
		  G_TYPE_UINT, &request_name_result,
		  G_TYPE_INVALID))
	{
		lose_gerror ("Failed to acquire org.fmddlmyy.Test", error);
	}



	obj = g_object_new (TEST_TYPE_OBJECT, NULL);
	dbus_g_connection_register_g_object (bus, "/TestObj", G_OBJECT (obj));



	printf ("service running\n");
	g_main_loop_run (mainloop);

	exit (0);
}

dbus_g_bus_get:创建一个总线
dbus_g_proxy_new_for_name:根据参数会创建org.freedesktop.DBus总线的/org/freedesktop/DBus对象的接口方法org.freedesktop.DBus的代理
dbus_g_proxy_call:执行代理函数,将org.fmddlmyy.Test总线注册上
dbus_g_connection_register_g_object:将对象/TestObj注册到总线org.fmddlmyy.Test
//example-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_introspectable;
	GError *error = NULL;
	char *introspect_data;
	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);
	}



	remote_object = dbus_g_proxy_new_for_name (bus,"org.fmddlmyy.Test","/TestObj","org.fmddlmyy.Test.Basic");
	if (!dbus_g_proxy_call (remote_object, "Add", &error,
		  G_TYPE_INT, 100, G_TYPE_INT, 999, G_TYPE_INVALID,
		  G_TYPE_INT, &sum, G_TYPE_INVALID))
	{
		lose_gerror ("Failed to call Add", error);
	}

	printf("sum is %d\n", sum);
	g_object_unref (G_OBJECT (remote_object));



	remote_object_introspectable = dbus_g_proxy_new_for_name (bus,"org.fmddlmyy.Test","/TestObj","org.freedesktop.DBus.Introspectable");
	if (!dbus_g_proxy_call (remote_object_introspectable, "Introspect", &error,
		  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));
	

	exit(0);
}
调用某个总线的服务很简单,基本是4个函数:
dbus_g_bus_get:获得总线
dbus_g_proxy_new_for_name:创建代理某个总线的某个接口的某个方法的代理
dbus_g_proxy_call:调用代理
g_object_unref :释放代理


编译时需要链接Glib库
root@ubuntu:/opt/ss/hello-dbus3-0.1/src# make
mode=execute dbus-binding-tool --prefix=test_obj --mode=glib-server --output=example-service-glue.h ./example-service.xml
make  all-am
make[1]: 正在进入目录 `/opt/ss/hello-dbus3-0.1/src'
gcc -DHAVE_CONFIG_H -I. -I.. -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include   -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include   -DDBUS_COMPILATION    -g -O2 -MT example-service.o -MD -MP -MF .deps/example-service.Tpo -c -o example-service.o example-service.c
mv -f .deps/example-service.Tpo .deps/example-service.Po
gcc  -g -O2   -o example-service example-service.o  -L/lib -ldbus-1 -lpthread -lrt   -pthread -lgobject-2.0 -lgthread-2.0 -lrt -lglib-2.0   -ldbus-glib-1
gcc -DHAVE_CONFIG_H -I. -I.. -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include   -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include   -DDBUS_COMPILATION    -g -O2 -MT example-client.o -MD -MP -MF .deps/example-client.Tpo -c -o example-client.o example-client.c
mv -f .deps/example-client.Tpo .deps/example-client.Po
gcc  -g -O2   -o example-client example-client.o  -L/lib -ldbus-1 -lpthread -lrt   -pthread -lgobject-2.0 -lgthread-2.0 -lrt -lglib-2.0   -ldbus-glib-1
make[1]:正在离开目录 `/opt/ss/hello-dbus3-0.1/src'

源码


参考
http://blog.csdn.net/fmddlmyy/article/details/3585730
http://www.fmddlmyy.cn/text52.html
https://en.wikipedia.org/wiki/D-Bus
https://www.freedesktop.org/wiki/Software/dbus/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值