在 Linux 中,Dbus 是一种进程间通信的方式。例如,像 Pidgin 即时通讯程序这样的应用程序允许其他程序查询或更改用户的状态(如可用、离开等)。另一个例子是网络管理器服务,它发布了当前活跃的互联网连接。那些偶尔连接到互联网的程序可以在最佳时机下载系统更新。

总线

消息沿着总线发送。服务将自己附加到这些总线上,并允许客户端向它们发送和接收消息。

主要有两种总线,系统总线和会话总线。系统总线上的服务影响整个系统,例如提供关于网络或磁盘驱动器的信息。会话总线上的服务提供对桌面上运行的程序的访问,例如 Pidgin。

import dbus

sys_bus = dbus.SystemBus()

对象和接口

附加到总线上的服务可以通过它们的知名名称进行联系。虽然这个名称可以是任何字符串,但通常格式是反向域名:例如,名为“CalcProgram”的电子表格程序,来自“My Corp Inc.”,其名称可以是“com.mycorp.CalcProgram”。

服务通过斜杠分隔的路径来发布对象(这似于网页)。如果某人在 Dbus 上知道这个路径,他们可以请求这个对象。

返回的对象不是完整的对象:它仅仅是指向服务的对象副本。它被称为代理对象。

proxy_for_cell_a2 = sys_bus.get_object('com.mycorp.CalcProgram', '/spreadsheet1/cells/a2')

在使用代理对象之前,我们需要指定它是哪种型的对象。我们通过创建一个接口对象来做到这一点。

cell_a2 = dbus.Interface(proxy_for_cell_a2, 'com.mycorp.CalcProgram.SpreadsheetCell')

可以调用为此型的对象设置的任何方法:

cell_a2.getContents()
名称 示例 描述
service well known name com.mycorp.CalcProgram 标识应用程序
path of an object /spreadsheet1/cells/a2 标识由服务发布的对象
interface com.mycorp.CalcProgram.SpreadsheetCell 标识我们期望的对象

dbus-python 示例

这些示例已在 dbus-python 0.83.0 中测试过。较老的库版本可能没有相同的接口。

调用接口的方法 / 列出 HAL 设备:

import dbus

bus = dbus.SystemBus()
hal_manager_object = bus.get_object('org.freedesktop.Hal', '/org/freedesktop/Hal/Manager')
hal_manager_interface = dbus.Interface(hal_manager_object, 'org.freedesktop.Hal.Manager')

# 调用接口的方法
print(hal_manager_interface.GetAllDevices())

# 通过代理对象访问方法,指定接口
method = hal_manager_object.get_dbus_method('GetAllDevices', 'org.freedesktop.Hal.Manager')
print(method())

# 通过代理对象调用方法,指定要使用的接口
print(hal_manager_object.GetAllDevices(dbus_interface='org.freedesktop.Hal.Manager'))

检查对象:

import dbus

bus = dbus.SystemBus()
hal_manager_object = bus.get_object(
    'org.freedesktop.Hal',          # 服务
    '/org/freedesktop/Hal/Manager'  # 发布的对象
)

introspection_interface = dbus.Interface(
    hal_manager_object,
    dbus.INTROSPECTABLE_IFACE,
)

# 可 introspectable 接口定义了一个属性 'Introspect',
# 它将返回一个描述对象接口的 XML 字符串
interface = introspection_interface.Introspect()
print(interface)

Avahi:

import dbus

sys_bus = dbus.SystemBus()

# 获取与 org.freedesktop.Avahi 对话的对象
raw_server = sys_bus.get_object('org.freedesktop.Avahi', '/')

# 对象支持接口。获取我们的 org.freedesktop.Avahi 对象的 org.freedesktop.Avahi.Server 接口。
server = dbus.Interface(raw_server, 'org.freedesktop.Avahi.Server')

# 所谓的文档位于 /usr/share/avahi/introspection/Server.introspect
print(server)
print(server.GetVersionString())
print(server.GetHostName())

pydbus 示例

这些示例已在 pydbus 0.2 和 0.3 中测试过。

调用接口的方法 / 列出 systemd 单元:

from pydbus import SystemBus

bus = SystemBus()
systemd = bus.get(
    '.systemd1'  # 服务名称 - 以 . 开头的名称会自动加上 org.freedesktop 前缀
    # 没有对象路径 - 它将设置为服务名称并转换为路径格式(/org/freedesktop/systemd1)
)

for unit in systemd.ListUnits()[0]:
    print(unit)

检查对象:

from pydbus import SystemBus

bus = SystemBus()
systemd = bus.get('.systemd1')

# 可 introspectable 接口定义了一个属性 'Introspect',
# 它将返回一个描述对象接口的 XML 字符串
print(systemd.Introspect()[0])

# introspection 数据会自动转换为 Python 的帮助系统数据
help(systemd)

Avahi:

from pydbus import SystemBus

bus = SystemBus()

# 获取与 org.freedesktop.Avahi 对话的对象
avahi = bus.get('.Avahi', '/')

# 查看对象的 API
help(avahi)

print(avahi.GetVersionString())
print(avahi.GetHostName())
Last modified: Friday, 31 January 2025, 1:49 AM