DBus有两种API接口,一种是直接使用DBUS的 low-level API,一种是使用Binding,Bindings有不同的类型,有PERL Binding、PYTHON Binding、GLIB Binding等。这里主要关注使用GLIB binding。和low-level API不同的是,GLIB binding则能够完成GLIB OBJECT的本地事件(native signal)与DBus事件的绑定,下面描述使用DBUS,Signal事件发送和接收的基本过程。
1、Signal被发送到DBus Daemon,这个过程如果使用low-level API,这个过程需要程序直接完成;如果使用GLIB Binding,则GLIB OBJECT发送本地的Signal时自动完成。这个本地的Signal,就是g_signal_emit方法发出的GLIB OBJECT的Signal。
2、Signal包含接口的标识、Signal的标识、以及发送者的标识、其他参数。
3、DBus上的任何进程可以提交Signal的“过滤规则”。
4、DBus Daemon根据Signal过滤规则,将Signal发送到各个进程。
5、Signal接收进程接到Signal进行处理,如果使用low-level API,则直接处理Signal;如果使用的是GLIB Binding,GLIB Binding将在其代理对象上触发一个本地事件(emit a native signal )
下面回到DBus-GLIB的例子程序,详细说明这个过程。DBus-GLIB Binding的例子运行过程如《初探DBUS(1)》一文所示(如果有疑问需要获取源码请参见初探DBUS(1)),在例子主干逻辑如下:
1、example-signal-recipient程序负责定期向发起example-signal-emitter程序emitHelloSignal远程方法调用
2、example-signal-emitter程序为emitHelloSignal的服务器端,接收到调用后,向example-signal-recipient发送HELLO_SIGNAL的SIGNAL事件
3、example-signal-recipient接收到事件并打印。
example-signal-emitter程序的分析如下:
(1)从example-signal-emitter.xml文件生成对应的example-signal-emitter-glue.h文件
example-signal-emitter.xml文件如下:
<?xml version="1.0" encoding="UTF-8" ?>
<node name="/">
<interface name="org.designfu.TestService">
<method name="emitHelloSignal">
</method>
<!-- Mark the signal as exported -->
<signal name="HelloSignal"/>
</interface>
</node>
命令行如下:
dbus-binding-tool --prefix=test_object --mode=glib-server --output=example-signal-emitter-glue.h ./example-signal-emitter.xml
example-signal-emitter-glue.h定义了本地的对象中哪个Signal与DBus的Signal绑定。example-signal-emitter-glue.h原码中定义了HelloSignal的DBus 的Signal与本地定义Signal绑定
const DBusGObjectInfo dbus_glib_test_object_object_info = {
0,
dbus_glib_test_object_methods,
1,
"org.designfu.TestService\0emitHelloSignal\0S\0\0\0",
"org.designfu.TestService\0HelloSignal\0\0",
"\0"
};
(2)example-signal-emitter.c中定义了一个GOBJECT风格的“对象” TestObject。TestObject的class_init方法定义了hello_signal 的本地Signal。关于GOBJECT的对象模型请查看GOBJECT的相关文档。
static void test_object_class_init (TestObjectClass *klass)
{
signals[HELLO_SIGNAL] =
g_signal_new ("hello_signal",
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);
}
这里有一个问题,名为“HelloSignal”的DBus事件如何同名为“hello_signal”关联的?这个问题可以从./dbus-gobject.c的export_signals 函数得到解答,该函数调用了s = _dbus_gutils_wincaps_to_uscore (signame);_dbus_gutils_wincaps_to_uscore这个函数将HelloSignal翻译成了hello_signal
(3)当example-signal-emitter在接收到emitHelloSignal远程方法调用中发出"hello_signal"的本地Signal
g_signal_emit (obj, signals[HELLO_SIGNAL], 0, "Hello");
本地的Signal如何触发DBus的Signal呢?到回example-signal-emitter的主函数继续分析
(3.1)初始化
DBusGConnection *bus;
DBusGProxy *bus_proxy;
GError *error = NULL;
TestObject *obj;
GMainLoop *mainloop;
guint request_name_result;
g_type_init ();
dbus_g_object_type_install_info (TEST_TYPE_OBJECT, &dbus_glib_test_object_object_info);
dbus_glib_test_object_object_info见第(1)步的的说明
(3.2)设置本地Signal与DBus Signal的绑定
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.designfu.TestService",
G_TYPE_UINT, 0,
G_TYPE_INVALID,
G_TYPE_UINT, &request_name_result,
G_TYPE_INVALID))
lose_gerror ("Failed to acquire org.designfu.TestService", error);
obj = g_object_new (TEST_TYPE_OBJECT, NULL);
dbus_g_connection_register_g_object (bus, "/org/designfu/TestService/object", G_OBJECT (obj));
printf ("test service running\n");
g_main_loop_run (mainloop);
exit (0);
dbus_g_connection_register_g_object方法中调用了上文提到的export_signals ,export_signals 对每个export的本地signal进行了如下的操作:
closure = dbus_g_signal_closure_new (connection, object, signame, (char*) iface);
g_closure_set_marshal (closure, signal_emitter_marshaller);
g_signal_connect_closure_by_id (object,
id,
0,
closure,
FALSE);
g_closure_add_finalize_notifier (closure, NULL,
dbus_g_signal_closure_finalize);
closure是什么呢?文档说“A GClosure represents a callback supplied by the programmer.” g_signal_connect_closure_by_id函数为每个本地的Signal(参数id,是本地Signal的ID)挂载一个处理回调的closure,closure中关键函数是signal_emitter_marshaller
static void
signal_emitter_marshaller (GClosure *closure,
GValue *retval,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data)
{
DBusGSignalClosure *sigclosure;
DBusMessage *signal;
DBusMessageIter iter;
guint i;
const char *path;
sigclosure = (DBusGSignalClosure *) closure;
g_assert (retval == NULL);
path = _dbus_gobject_get_path (sigclosure->object);
g_assert (path != NULL);
signal = dbus_message_new_signal (path,
sigclosure->sigiface,
sigclosure->signame);
if (!signal)
{
g_error ("out of memory");
return;
}
dbus_message_iter_init_append (signal, &iter);
/* First argument is the object itself, and we can't marshall that */
for (i = 1; i < n_param_values; i++)
{
if (!_dbus_gvalue_marshal (&iter,
(GValue *) (&(param_values[i]))))
{
g_warning ("failed to marshal parameter %d for signal %s",
i, sigclosure->signame);
goto out;
}
}
dbus_connection_send (DBUS_CONNECTION_FROM_G_CONNECTION (sigclosure->connection),
signal, NULL);
out:
dbus_message_unref (signal);
}
可以很清晰的看到,dbus_connection_send 的过程,于是,本地的signal触发--〉dbus_g_closure-->signal_emitter_marshaller,在 signal_emitter_marshaller将DBus的Signal发送了出去。
-----------------------------------------------------------------------------------------------------------------
example-signal-recipient的主干逻辑代码如下:
(1)初始化Session Bus连接,并获取远程对象。
DBusGConnection *bus;
DBusGProxy *remote_object;
GError *error = NULL;
GMainLoop *mainloop;
g_type_init ();
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);
/* We use _for_name_owner in order to track this particular service
* instance, which lets us receive signals.
*/
remote_object = dbus_g_proxy_new_for_name (bus,
"org.designfu.TestService",
"/org/designfu/TestService/object",
"org.designfu.TestService");
if (!remote_object)
lose_gerror ("Failed to get name owner", error);
(2)被注释掉的重要步骤:注册Signal处理的marshaller。
由于例子使用的远程调用方法emitHelloSignal不带参数,因此可以使用系统内置的marshaller,因此例子程序中将 dbus_g_object_register_marshaller注释了。这里参照pidgin 项目(另一个使用DBus的著名开源项目)的DBus用法,将该步骤补上,在pidgin的例子中,Signal的interface名为"im.pidgin.purple.PurpleInterface"
(2.1)查看Signal的“函数原型”,使用dbus-monitor命令进行查找:
命令行:dbus-monitor type=signal interface="im.pidgin.purple.PurpleInterface"
结果:
signal sender=:1.21 -> dest=(null destination) path=/im/pidgin/purple/PurpleObject; interface=im.pidgin.purple.PurpleInterface; member=ReceivedImMsg
int32 1097
string "mybuddy@hotmail.com"
string "<FONT FACE="Times"><FONT COLOR="#000000">Hi!</FONT></FONT>"
int32 8728
uint32 0
(2.2)生成marshal.list文件
内容如下:
VOID:INT,STRING,STRING,INT,UINT
其含义是:返回为VOID,参数类型按次序为
INT,STRING,STRING,INT,UINT
(2.3)生成marshal.h和marshal.c
glib-genmarshal --header --prefix=marshal marshal.list > marshal.h
glib-genmarshal --body --prefix=marshal marshal.list > marshal.c
(2.4)注册marshaller
dbus_g_object_register_marshaller(marshal_VOID__INT_STRING_STRING_INT_UINT,
G_TYPE_NONE, G_TYPE_INT, G_TYPE_STRING,
G_TYPE_STRING, G_TYPE_INT, G_TYPE_UINT,
G_TYPE_INVALID);
(3)设置需处理的HelloSignal事件
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);
(4)设置一个定时器,定期发起emitHelloSignal调用。
定时器回调方法如下:
static gboolean emit_signal (gpointer arg)
{
DBusGProxy *proxy = arg;
dbus_g_proxy_call_no_reply (proxy, "emitHelloSignal", G_TYPE_INVALID);
return TRUE;
}
分享到:
相关推荐
DBus-Glib 是 GNU 标准库,在 Dbus 接口上封装,方便上层服务与应用更好的使用。以下是对 DBus-Glib 的使用框架的详细介绍: 一、背景介绍 Phoenix 平台从安全的角度考虑,广泛的使用 DBUS 进行进程间通讯。DBus ...
DBUS-GLIB在此基础上封装了DBUS的通信机制,使之能够更好地与基于GLib的应用程序集成。 ### DBUS-GLIB API 说明 DBUS-GLIB的核心组件之一是它提供的API集合,这些API使得开发者可以方便地在程序中实现DBUS消息的...
DBus-Glib 0.98 是一个用于在Glib(GLib库)环境中与D-Bus消息总线交互的库。D-Bus是一种轻量级的、进程间通信(IPC)机制,允许不同应用程序之间共享服务和数据。Glib是GTK+图形用户界面库的基础,提供了一系列通用...
DBus 是一个轻量级的消息总线系统,允许不同进程之间交换消息,而DBus-Glib 是一个 C 语言库,它为DBus 提供了更方便的绑定,尤其适合用在 GLib 和 GTK+ 的应用程序中。在这个实例中,我们将探讨如何在 C/C++ 中使用...
. ├── dbus-1.12.20.tar.gz ├── dbus-glib-0.106.tar.gz ├── expat-2.3.0.tar.bz2 ├── glib-2.34.1.tar.xz ├── libffi-3.3.tar.gz ├── README └── zlib-1.2.11.tar.gz
dbus-glib-0.86-5.el6.i686.rpm
dbus-glib-devel-0.86-5.el6.i686.rpm
离线安装包,亲测可用
官方离线安装包,亲测可用
离线安装包,亲测可用
官方离线安装包,亲测可用
官方离线安装包,亲测可用
基于dbus-1.13.6版本编译意味着该版本包含了DBus的最新特性,并且在Windows 10环境下进行了适配。DBus 1.13.6是一个稳定版本,包含了多项改进和修复,确保在Windows上的稳定性和兼容性。同时,编译使用了Visual ...
dbus-libs-1.2.24-5.el6_1.i686.rpm
3. **异步操作**:考虑到JavaScript的事件驱动特性,`dbus-native` 的大部分方法都是异步的,如`method.call()`、`signal.on()`,这使得与D-Bus服务的交互不会阻塞主线程。 4. **错误处理**:库提供了错误处理机制,...
官方离线安装包,亲测可用
windows DBus的支持
DBus-core详解: D-Bus,全称为Desktop Bus,是一种低延迟、异步的IPC(进程间通信)协议。它主要用于Linux、BSD以及其他自由的类UNIX系统。D-Bus的目的是作为各种早期临时机制的替代品,这些机制在Linux桌面早期...
官方离线安装包,亲测可用
DBus-1.12.10是DBus的一个特定版本,这里我们深入探讨一下这个版本的细节和相关知识点。 DBus的核心功能是作为进程间通信(IPC, Inter-Process Communication)的中间件,它提供了一种标准的方式来让应用程序交换...