`
larva
  • 浏览: 11731 次
  • 性别: Icon_minigender_1
  • 来自: 贵州
最近访客 更多访客>>
社区版块
存档分类
最新评论

使用 D-BUS 连接桌面应用程序

阅读更多
D-BUS 是一个大有前途的消息总线和活动系统,正开始深入地渗透到 Linux 桌面之中。了解创建它的原因、它的用途以及发展前景。
<!-- START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --> <!-- END RESERVED FOR FUTURE USE INCLUDE FILES-->

D-BUS 本质上是 进程间通信(inter-process communication) (IPC)的一个实现。不过,有一些 特性使得 D-BUS 远远不是“只是另一个 IPC 实现”。有很多不同的 IPC 实现,因为每一个都定位于解决 特定的明确定义的问题。CORBA 是用于面向对象编程中复杂的 IPC 的一个强大的解决方案。DCOP 是一个 较轻量级的 IPC 框架,功能较少,但是可以很好地集成到 K 桌面环境中。SOAP 和 XML-RPC 设计用于 Web 服务,因而使用 HTTP 作为其传输协议。D-BUS 设计用于桌面应用程序和 OS 通信。

桌面应用程序通信

典型的桌面都会有多个应用程序在运行,而且,它们经常需要彼此进行通信。DCOP 是一个用于 KDE 的 解决方案,但是它依赖于 Qt,所以不能用于其他桌面环境之中。类似的,Bonobo 是一个用于 GNOME 的 解决方案,但是非常笨重,因为它是基于 CORBA 的。它还依赖于 GObject,所以也不能用于 GNOME 之外。 D-BUS 的目标是将 DCOP 和 Bonobo 替换为简单的 IPC,并集成这两种桌面环境。由于尽可能地减少了 D-BUS 所需的依赖,所以其他可能会使用 D-BUS 的应用程序不用担心引入过多依赖。

桌面/操作系统通信

术语“操作系统”在这里不仅包括内核,还包括系统后台进程。例如,通过使用 D-BUS 的 udev (Linux 2.6 中取代 devfs 的, 提供动态 /dev 目录),当设备(比如一个 USB 照相机)插入时会发放出一个信号。 这样可以更紧密地将硬件集成到桌面中,从而改善用户体验。

D-BUS 特性

D-BUS 有一些有趣的特性,使其像是一个非常有前途的选择。

协议是低延迟而且低开销的,设计得小而高效,以便最小化传送的往返时间。另外,协议是二进制的,而 不是文本的,这样就排除了费时的序列化过程。由于只面向本地机器处理的使用情形,所以所有的消息 都以其自然字节次序发送。字节次序在每个消息中声明,所以如果一个 D-BUS 消息通过网络传输到 远程的主机,它仍可以被正确地识别出来。

从开发者的角度来看,D-BUS 是易于使用的。有线协议容易理解,客户机程序库以直观的方式对其进行 包装。

程序库还设计用于为其他系统所包装。预期,GNOME 将使用 GObject 创建包装 D-BUS 的包装器 (实际上这些已经部分存在了,将 D-BUS 集成入它们的事件循环),KDE 将使用 Qt 创建类似的 包装器。由于 Python 具有面向对象特性和灵活的类型,已经有了具备类似接口的 Python 包装器。

最后,D-BUS 正在 freedesktop.org 的保护下进行开发,在那里,来自 GNOME、KDE 以及 其他组织的对此感兴趣的成员参与了设计与实现。

 




回页首


D-BUS 的内部工作方式

典型的 D-BUS 设置将由几个总线构成。将有一个持久的 系统总线(system bus) ,它在 引导时就会启动。这个总线由操作系统和后台进程使用,安全性非常好,以使得任意的应用程序 不能欺骗系统事件。还将有很多 会话总线(session buses) ,这些总线当用户登录后启动,属于 那个用户私有。它是用户的应用程序用来通信的一个会话总线。当然,如果一个应用程序需要接收 来自系统总线的消息,它不如直接连接到系统总线 —— 不过,它可以发送的消息将是受限的。

一旦应用程序连接到了一个总线,它们就必须通过添加 匹配器(matchers) 来声明它们希望 收到哪种消息。匹配器为可以基于接口、对象路径和方法进行接收的消息指定一组规则(见后)。 这样就使得应用程序可以集中精力去处理它们想处理的内容,以实现消息的高效路由,并保持总线 上消息的预期数量,以使得不会因为这些消息导致所有应用程序的性能下降并变得很慢。

对象

本质上,D-BUS 是一个对等(peer-to-peer)的协议 —— 每个消息都有一个源和一个目的。这些地址 被指定为 对象路径 。概念上,所有使用 D-BUS 的应用程序都包括一组 对象 ,消息发送到 或者发送自特定对象 —— 不是应用程序 —— 这些对象由对象路径来标识。

另外,每个对象都可以支持一个或多个 接口(interfaces) 。这些接口看起来类似于 Java 中 的接口或者 C++ 中的纯粹的虚类(pure virtual classes)。不过,没 有选项来检查对象是否实现了它们所声明的接口,而且也没有办法可以调查对象内部以使列出其支持的接口。 接口用于名称空间和方法名称,因此一个单独的对象可以有名称相同而接口不同的多个方法。

消息

在 D-BUS 中有四种类型的消息:方法调用(method calls)、方法返回(method returns)、信号(signals) 和错误(errors)。要执行 D-BUS 对象的方法,您需要向对象发送一个方法调用消息。它将完成一些处理并返回 一个方法返回消息或者错误消息。信号的不同之处在于它们不返回任何内容:既没有“信号返回”消息,也没有 任何类型的错误消息。

消息也可以有任意的参数。参数是强类型的,类型的范围是从基本的非派生类型(布尔(booleans)、 字节(bytes)、整型(integers))到高层次数据结构(字符串(strings)、数组( arrays)和字典(dictionaries))。

服务

服务(Services) 是 D-BUS 的最高层次抽象,它们的实现当前还在不断发展变化。应用程序 可以通过一个总线来注册一个服务,如果成功,则应用程序就已经 获得 了那个服务。其他应用 程序可以检查在总线上是否已经存在一个特定的服务,如果没有可以要求总线启动它。服务抽象的细节 —— 尤其是服务活化 —— 当前正处于发展之中,应该会有变化。

 




回页首


用例

尽管 D-BUS 相对较新,但是却迅速地得到了采用。如前所述,可以构建具有 D-BUS 支持的 udev 以使得当热插拔(hot-plug)设备时它可以发送一个信号。 任何应用程序都可以侦听这些事件并当接收到这些事件时执行动作。例如,gnome-volume-manager 可以检测到 USB 存储棒的插入并自动挂载它;或者,当插入一个数码相机时它可以自动下载照片。

一个更为有趣但很不实用的例子是 Jamboree 和 Ringaling 的结合。Jamboree 是一个简单的音乐播放器, 它具有 D-BUS 接口,以使得它可以被告知播放、到下一首歌、改变音量等等。Ringaling 是一个小程序, 它打开 /dev/ttyS0(一个串行端口)并观察接收到的内容。当 Ringaling 发现文本“RING”时,就通过 D-BUS 告知 Jamboree 减小音量。最终的结果是,如果您的计算机上插入了一个调制解调器,而且电话 铃响,则音乐音量就会为您减小。 正是计算机所追求的!

 




回页首


代码示例

现在,让我们来接触一些使用 D-BUS 代码的示例。

dbus-ping-send.c 每秒通过会话总线发送一个参数为字符串“Ping!”的信号。我使用 Glib 来 管理总线,以使得我不需要自己来处理总线的连接细节。


清单 1. dbus-ping-send.c

#include <glib.h>
#include <dbus/dbus-glib.h>
static gboolean send_ping (DBusConnection *bus);
int
main (int argc, char **argv)
{
  GMainLoop *loop;
  DBusConnection *bus;
  DBusError error;
  /* Create a new event loop to run in */
  loop = g_main_loop_new (NULL, FALSE);
  /* Get a connection to the session bus */
  dbus_error_init (&error);
  bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
  if (!bus) {
    g_warning ("Failed to connect to the D-BUS daemon: %s", error.message);
    dbus_error_free (&error);
    return 1;
  }
  /* Set up this connection to work in a GLib event loop */
  dbus_connection_setup_with_g_main (bus, NULL);
  /* Every second call send_ping() with the bus as an argument*/
  g_timeout_add (1000, (GSourceFunc)send_ping, bus);
  /* Start the event loop */
  g_main_loop_run (loop);
  return 0;
}
static gboolean
send_ping (DBusConnection *bus)
{
  DBusMessage *message;
  /* Create a new signal "Ping" on the "com.burtonini.dbus.Signal" interface,
   * from the object "/com/burtonini/dbus/ping". */
  message = dbus_message_new_signal ("/com/burtonini/dbus/ping",
                                     "com.burtonini.dbus.Signal", "Ping");
  /* Append the string "Ping!" to the signal */
  dbus_message_append_args (message,
                            DBUS_TYPE_STRING, "Ping!",
                            DBUS_TYPE_INVALID);
  /* Send the signal */
  dbus_connection_send (bus, message, NULL);
  /* Free the signal now we have finished with it */
  dbus_message_unref (message);
  /* Tell the user we send a signal */
  g_print("Ping!\n");
  /* Return TRUE to tell the event loop we want to be called again */
  return TRUE;
}

 

main 函数创建一个 GLib 事件循环,获得会话总线的一个连接, 并将 D-BUS 事件处理集成到 Glib 事件循环之中。然后它创建了一个名为 send_ping 间隔为一秒的计时器,并启动事件循环。

send_ping 构造一个来自于对象路径 /com/burtonini/dbus/ping 和 接口 com.burtonini.dbus.Signal 的新的 Ping 信号。然后,字符串 “Ping!”作为参数添加到信号中并通过总线发送。在标准输出中会打印一条消息以让用户知道发送了 一个信号。

当然,不应该向总线发送了信号而没有任何程序在侦听它们……于是我们需要:


清单 2. dbus-ping-listen.c

#include <glib.h>
#include <dbus/dbus-glib.h>
static DBusHandlerResult signal_filter 
      (DBusConnection *connection, DBusMessage *message, void *user_data);
int
main (int argc, char **argv)
{
  GMainLoop *loop;
  DBusConnection *bus;
  DBusError error;
  loop = g_main_loop_new (NULL, FALSE);
  dbus_error_init (&error);
  bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
  if (!bus) {
    g_warning ("Failed to connect to the D-BUS daemon: %s", error.message);
    dbus_error_free (&error);
    return 1;
  }
  dbus_connection_setup_with_g_main (bus, NULL);
  /* listening to messages from all objects as no path is specified */
  dbus_bus_add_match (bus, "type='signal',interface='com.burtonini.dbus.Signal'");
  dbus_connection_add_filter (bus, signal_filter, loop, NULL);
  g_main_loop_run (loop);
  return 0;
}
static DBusHandlerResult
signal_filter (DBusConnection *connection, DBusMessage *message, void *user_data)
{
  /* User data is the event loop we are running in */
  GMainLoop *loop = user_data;
  /* A signal from the bus saying we are about to be disconnected */
  if (dbus_message_is_signal 
        (message, DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL, "Disconnected")) {
    /* Tell the main loop to quit */
    g_main_loop_quit (loop);
    /* We have handled this message, don't pass it on */
    return DBUS_HANDLER_RESULT_HANDLED;
  }
  /* A Ping signal on the com.burtonini.dbus.Signal interface */
  else if (dbus_message_is_signal (message, "com.burtonini.dbus.Signal", "Ping")) {
    DBusError error;
    char *s;
    dbus_error_init (&error);
    if (dbus_message_get_args 
       (message, &error, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID)) {
      g_print("Ping received: %s\n", s);
      dbus_free (s);
    } else {
      g_print("Ping received, but error getting message: %s\n", error.message);
      dbus_error_free (&error);
    }
    return DBUS_HANDLER_RESULT_HANDLED;
  }
  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}

 

这个程序侦听 dbus-ping-send.c 正在发出的信号。 main 函数 和前面一样启动,创建一个到总线的连接。然后它声明愿意当具有 com.burtonini.dbus.Signal 接口的信号被发送时得到通知,将 signal_filter 设置为通知函数, 然后进入事件循环。

当满足匹配的消息被发送时, signal_func 会被调用。不过,它也将会 收到来自总线本身的总线管理信号。要确定接收到消息时应该做些什么,仅仅需要检验消息头。如果消息是 总线断开信号,则事件循环终止,因为侦听一个不存在的总线是没有意义的。(告知总线信号已经处理)。 然后,将到来的消息与期望的消息相比较,如果成功,则解出参数并输出。如果到来的消息不是其中的任何一个, 则告知总线没有处理那个消息。

那两个示例使用了低层的 D-BUS 程序库,这个程序库是完全的,但是当您想创建服务和很多对象时, 使用起来冗长得令人厌倦。有正在开发中的 C# 和 Python 包装器,提供了非常接近于 D-BUS 的逻辑 模型的编程接口。作为一个示例,这里是用 Python 重新对 ping/listen 示例进行了更为精致的实现。 由于 Python 绑定模拟了逻辑接口,所以不可能不通过一个服务来发送信号。所以这个例子也要创建 一个服务:


清单 3. dbus-ping-send.py

#! /usr/bin/env python
import gtk
import dbus
# Connect to the bus
bus = dbus.Bus()
# Create a service on the bus
service = dbus.Service("com.burtonini.dbus.SignalService", bus)
# Define a D-BUS object
class SignalObject(dbus.Object):
    def __init__(self, service):
        dbus.Object.__init__(self, "/", [], service)
# Create an instance of the object, which is part of the service
signal_object = SignalObject(service)
def send_ping():
    signal_object.broadcast_signal("com.burtonini.dbus.Signal", "Ping")
    print "Ping!"
    return gtk.TRUE
# Call send_ping every second to send the signal
gtk.timeout_add(1000, send_ping)
gtk.main()

 

代码大部分是不言而明的:获得一个到总线的连接并注册 com.burtonini.dbus.SignalService 服务。然后创建一个最小限度的 D-BUS 对象, 这个对象每秒广播一个信号。代码比相应的 C 代码 更简单, 但是需要做 Python 绑定的工作。(例如,没有方法向信号添加参数。)


清单 4. dbus-ping-listen.py

#! /usr/bin/env python
import gtk
import dbus
bus = dbus.Bus()
def signal_callback(interface, signal_name, service, path, message):
    print "Received signal %s from %s" % (signal_name, interface)
# Catch signals from a specific interface and object, and call signal_callback
# when they arrive.
bus.add_signal_receiver(signal_callback,
                        "com.burtonini.dbus.Signal", # Interface
                        None, # Any service
                        "/" # Path of sending object
                        )
# Enter the event loop, waiting for signals
gtk.main()

 

此代码比 dbus-ping-listen.c 中相应的 C 代码 更简明,也更容易读懂。此外, 有些地方需要做绑定的工作(当调用 bus.add_signal_receiver 时,用户必须传入 一个接口和一个对象路径;否则会创建不正常的匹配器)。这是一个微不足道的缺陷,一旦这个缺陷被修正,就可以 去服务和对象路径参数除,这将进一步提高代码的可读性。

 

分享到:
评论

相关推荐

    D-Bus 详解.doc

    这些库进一步简化了D-Bus的使用难度,让开发者能够更容易地集成D-Bus到自己的应用程序中。 #### 四、D-Bus的工作原理 D-Bus支持两种主要类型的总线: 1. **系统总线**:用于操作系统和后台进程之间的通信。安全性...

    D-bus-1.4.1.tar.gz

    D-Bus的核心概念是“总线”,它是一个系统服务,负责管理连接到它的应用程序,并转发它们之间的消息。这些消息可以是简单的同步调用,也可以是异步通知,甚至可以用于传输文件或大块数据。D-Bus提供了两个主要的总线...

    Bluez and D-Bus

    为了进一步提高蓝牙设备在Linux系统中的可用性和兼容性,D-Bus框架被引入到Bluez中,从而实现了不同应用程序之间的通信和蓝牙功能的统一管理。 #### Bluez项目简介 Bluez项目是Linux内核中用于支持蓝牙协议的一组...

    D-bus 学习教程

    D-Bus旨在替代这些方案,提供一个跨桌面环境的统一接口,让应用程序无需考虑底层实现的复杂性。 D-Bus 由三层架构组成: 1. **函数库** - `libdbus`,这是D-Bus的核心,提供低级别的API,允许应用程序直接与其他...

    D-Bus Specification 0.31

    D-Bus的设计目的是提供一种简单而灵活的方式,使不同的应用程序或库能够相互通信。 #### 二、修订历史概览 本节将重点介绍D-Bus规格书版本0.31的关键变更及其意义。 ##### 1. **不要求实现特定搜索路径为最低...

    d-bus-1.10.16.tar.gz

    客户端是使用DBus接口的应用程序,服务器则管理消息传递,而代理则是介于两者之间的,负责处理特定服务的请求。 2. **消息协议**: DBus使用自己的二进制消息协议,定义了消息的结构、类型和交换规则。消息可以是...

    Go-dbus-原生Go绑定D-Bus消息总线系统

    D-Bus是一种跨进程通信机制,常用于Linux桌面环境中的服务间通信,它提供了低级别的消息传递和接口定义,使得应用程序能够以标准化的方式互相协作。 在Go-dbus库中,主要涉及以下核心概念和技术点: 1. **D-Bus...

    D-BUS实例讲解

    - **功能**: 在多个应用程序之间转发消息,起到桥梁作用。 ##### 1.3 支持D-BUS系统的消息总线类型 - **系统总线**: 主要用于系统与应用之间的通信。 - **会话总线**: 用于同一用户会话下的不同应用之间的通信。 #...

    linux DBUS 实例讲解

    2. **客户端(Client)**:客户端是指需要使用D-Bus进行通信的应用程序。客户端可以发送请求消息给服务端,也可以监听来自服务端的通知消息。 3. **服务端(Server)**:服务端是指提供特定功能或服务的应用程序。...

    dbus-core详解

    了解D-Bus的工作原理和使用方法,对于开发基于Linux和类UNIX系统的应用程序,尤其是需要与其他程序进行交互的应用程序来说,是非常重要的。通过D-Bus,开发者可以更容易地创建能够在不同应用程序之间共享功能和数据...

    dbus-broker:Linux D-Bus消息代理

    DBus-Broker是Linux系统中的一种D-Bus消息代理,它主要负责进程间通信(IPC,Inter-Process Communication)中的消息传递。...通过深入研究和实践,开发者可以更好地利用其优势,构建更高效、安全的分布式应用程序。

    dbus使用介绍.zip

    D-Bus是一个在Linux和其他Unix-like系统中广泛使用的进程间通信(IPC)机制,它允许应用程序之间进行高效、异步的消息传递。这个压缩包“dbus使用介绍.zip”包含了一个关于如何使用D-Bus的详细指南,以及一个简单的...

    dbus 使用介绍,包含一个例子,包括配置文件介绍及自启动介绍

    - **D-Bus 支持库**:这是一个客户端库,为应用程序提供与D-Bus总线交互所需的接口。 - **D-Bus 服务进程 (D-Bus Daemon)**:这个进程作为消息总线,负责管理连接到它的各个进程之间的通信。进程可以通过调用支持库...

    crystal-dbus:与D-Bus的晶体绑定

    它允许应用程序发送和接收消息,调用远程对象的方法,甚至订阅事件。在水晶(Crystal)这种静态类型的、基于LLVM的编程语言中,`crystal-dbus`库是开发者与D-Bus接口交互的桥梁。 **水晶(Crystal)语言简介** ...

    进程间通信

    在实现层面,D-Bus 支持点对点通信,通过本地套接字(AF_UNIX)在应用程序和 bus daemon 之间建立连接。bus daemon 负责处理消息寻址和分发,使得应用程序不必直接关心消息的接收方。 消息的发送过程大致如下: 1. ...

    Python库 | mpris_server-0.1.8-py2.py3-none-any.whl

    Python库是开发者在编程时经常会用到的工具,它们提供了预定义的功能,使得开发者能够快速构建应用程序,而无需从零开始编写所有代码。`mpris_server`是一个针对Python的库,版本为0.1.8,它是一个可适用于Python 2...

    PyPI 官网下载 | chromecast_mpris-0.6.9.tar.gz

    而MPRIS则是一种D-Bus接口规范,允许应用程序之间共享音乐播放控制信息,常见于Linux桌面环境中的音乐播放器。通过将Chromecast与MPRIS结合,我们可以实现对Chromecast设备的远程控制,例如从Linux桌面环境控制...

    gdbus-example:GDBUS 示例

    GDBus 提供了一种安全、高效的通信方式,使得不同的应用程序和服务能够相互协作。这个"**gdbus-example**"是一个示例项目,旨在帮助开发者理解如何在他们的应用中使用 GDBus。 首先,我们来深入了解一下 GDBus。...

Global site tag (gtag.js) - Google Analytics