Qt D-Bus

Introduction

D-Bus是一种进程间通信(IPC)和远程过程调用(RPC)机制, 最初是为Linux开发, 旨在用一个统一的协议取代现有的竞争IPC方案. 它还允许系统及进程(如打印机和硬件驱动程序服务)与用户进程间通信.

它使用一种快速的二进制消息传递协议, 具有低延时, 低开销等特点, 适合同一机器上的进程间通信. D-Bus规范由 freedesktop.org 项目定义, 各方均可使用.

通信通常通过一个中心服务程序进行, 这个中心服务程序被称为 "bus" (总线), 但也可以直接进程间通信. 在总线上通信时, 应用程序可以查询哪些应用程序和服务可用, 并根据需要激活一个.

总线

D-Bus用于多对多通信. 在任何应用程序连接总线前, 必须启动一个中心服务器: 这个服务器负责跟踪连接的应用程序, 并将消息从源正确地路由到目的地.

此外, D-Bus定义了两个知名的总线: 系统总线和会话总线. 这些总线的特殊之处是它们具有良好的语义: 一些服务可以在一个或两个总线中找到.

例如, 如果应用程序需要查询连接到计算机的硬件设备列表, 可能会与系统总线上的可用服务通信; 而打开用户网络浏览器的服务可能在会话总线上找到.

在系统总线上, 人们还可以期望发现每个应用程序可以提供哪些服务的限制. 因此, 如果某个服务存在, 那么它是由受信任的应用程序提供的.

基本概念

消息

在底层, 应用程序通过D-Bus相互发送消息通信. 消息用于转发远程过程调用以及与之相关的回复和错误. 在D-Bus上使用消息时, 消息有一个目的地, 这意味着它们只发送给感兴趣的各方, 避免由于 "拥挤" 或广播而造成的拥堵.

然而, 一种被称为 "信号消息" (基于Qt的 Signals and Slots 机制)没有预定义的目的地. 由于其目的是在一对多上下文中使用, 因此信号消息采用 "选择加入" 机制.

Qt D-Bus模块将消息的低级概念完全封装到Qt开发人员熟悉的更简单, 面向对象的方法中. 在大多数情况下, 开发人员不必担心发送或接收消息.

服务名

应用程序通过总线进行通信时, 会获得所谓的 "服务名称": 即应用程序如何选择让同一总线上的其他应用程序所知. 服务名称由D-Bus总线守护进程代理, 用于将消息从一个应用程序路由到另一个应用. 服务名称的概念与IP地址和主机名类似: 根据计算机向网络提供的服务, 计算机通常有一个IP地址, 并且可能有一个或多个与之相关的主机名.

另一方面, 如果不使用总线, 也不使用服务名称. 如果我们再次将其与计算机网络进行比较, 这将等同于点对点网络: 由于对等方是已知的, 因此不需要使用主机名来查找它或其IP地址.

D-Bus服务名称的格式实际上与主机名非常相似: 它是一个由字母和数字点分隔的序列. 通常的做法是使用定义服务的组织域名命名服务名称.

例如, D-Bus服务使用 freedesktop.org 定义, 在总线上以下列服务名称查找:


  org.freedesktop.DBus

对象路径

与网络主机一样, 应用程序通过导出对象向其他应用程序提供特定服务. 这些对象是分层组织的, 很像从 QObject 派生的类所拥有的父子关系. 然而, 一个不同之处在于, 存在 "根对象"的概念, 即所有对象都作为最终父对象.

如果我们继续与Web服务进行类比, 对象路径等同于URL的路径部分:

与URL一样, D-Bus中的对象路径类似于文件系统上的路径名: 它们是斜杠分隔的标签, 每个标签由字母, 数字和下划线 ("_")组成. 它们必须始终以斜杠开头, 而不能以斜杠结尾.

接口

接口类似于C++抽象类和Java的 interface 关键字, 并声明调用者和被调用者之间建立的 "契约" . 也就是说, 它们确定了可用的方法, 信号和属性名称, 以及在建立通信时双方预期的行为.

Qt在 插件系统中使用了一种非常相似的机制: C++中的基类通过 Q_DECLARE_INTERFACE() 宏与一个唯一的标识符相关联.

事实上, D-Bus接口名称的命名方式类似于Qt插件系统所建议的: 标识符通常由定义这个接口的实体域名.

备忘单

为了便于记住命名格式及其用途, 可以使用下表:

D-Bus ConceptAnalogyName format
Service nameNetwork hostnamesDot-separated ("looks like a hostname")
Object pathURL path componentSlash-separated ("looks like a path")
InterfacePlugin identifierDot-separated

调试

在开发使用D-Bus的应用程序时, 有时能够查看每个应用程序通过总线发送和接收的消息的信息是很有用的.

在运行每个应用程序之前设置 QDBUS_DEBUG 环境变量, 启用此功能. 例如, 我们可以通过以下方式调试示例 D-Bus Remote Controlled Car Example:


  examples/dbus/remotecontrolledcar/controller/controller &
  QDBUS_DEBUG=1 examples/dbus/remotecontrolledcar/car/car &

有关消息的信息将写入启动应用程序的控制台.

Further Reading

The following documents contain information about Qt's D-Bus integration features, and provide details about the mechanisms used to send and receive type information over the bus: