dbus
D-Bus 的历史与引入目的
-
起源:D-Bus(Desktop Bus)由 Red Hat 于 2006 年发布,作为freedesktop.org 项目的一部分。
-
背景:它旨在统一 Linux 桌面环境(如 GNOME 和 KDE)之间的通信机制,替代早期的 CORBA(GNOME)和 DCOP(KDE)等复杂或不兼容的 IPC 系统。
-
目标:
-
简化进程间通信(IPC)
-
提供统一、轻量、可扩展的通信机制
-
支持桌面组件之间的模块化协作
-
🎯 D-Bus 的主要用途(Use Cases)
-
桌面应用通信:如 GNOME Shell 与音量控制器、文件管理器之间的交互
-
系统事件通知:如 USB 插入、网络状态变化、电源管理
-
服务集成:如 Bluetooth、NetworkManager、systemd 等系统服务与用户应用之间的桥梁
-
单实例应用协调:确保某些应用只运行一个实例(如浏览器)
🧱 架构设计概览
🔧 核心组件
| 组件 | 说明 |
|---|---|
| Bus Daemon | 中央消息路由器,负责转发消息 |
| System Bus | 所有用户共享的系统级总线(如 Bluetooth) |
| Session Bus | 每个用户会话独立的总线(如桌面应用) |
| Client Libraries | 提供 API,供应用连接、发送、接收消息 |
📡 通信机制
-
使用 UNIX 域套接字(AF_UNIX) 进行本地通信
-
消息包括 头部 + 数据体,支持:
-
方法调用(request-response)
-
信号广播(事件通知)
-
属性访问(读写状态)
-
🧩 接口设计与命名规范
🧠 命名规则(类似 Java 包名)
-
服务名:
org.freedesktop.NetworkManager -
接口名:
org.freedesktop.NetworkManager.Device -
对象路径:
/org/freedesktop/NetworkManager/Devices/eth0
📦 接口组成
| 类型 | 说明 |
|---|---|
| 方法(Method) | 可调用的函数 |
| 信号(Signal) | 广播事件,所有监听者接收 |
| 属性(Property) | 状态值,可读写 |
🔍 支持接口自省(Introspection)
-
所有服务可通过标准接口
org.freedesktop.DBus.Introspectable返回 XML 格式的接口描述 -
客户端可动态查询服务支持哪些方法、信号、属性
🧪 使用方法概览
🧭 编程步骤(以 C 或 Python 为例)
-
连接总线(系统或会话)
-
注册服务名(服务端)
-
监听消息或发出方法调用
-
处理消息并返回响应
-
可选:发送信号、设置属性
🧰 支持语言
-
C(libdbus)
-
C++(QtDBus)
-
Python(dbus-python、dasbus)
-
Rust、Go、JavaScript 等也有绑定
📘 示例场景
-
GNOME 使用 D-Bus 控制音量、挂载 USB、扩展 Shell
-
KDE 使用 D-Bus 管理网络、电源、通知
-
systemd 使用 D-Bus 提供服务控制接口
-
BlueZ(蓝牙)通过 D-Bus 提供设备发现与连接控制
🧠 总结
D-Bus 是 Linux 世界中不可或缺的通信机制,它:
-
简化了应用与服务之间的协作
-
提供了统一的接口设计与发现机制
-
支持多语言开发与模块化架构
-
是现代 Linux 桌面和系统服务的基础通信桥梁
示例一:D-Bus 服务(Systemd)
服务名:org.freedesktop.systemd1
这是 systemd 提供的 D-Bus 服务,用于控制和查询系统服务。
-
对象路径:
/org/freedesktop/systemd1 -
接口名:
org.freedesktop.systemd1.Manager -
常用方法:
-
StartUnit("sshd.service", "replace"):启动 SSH 服务 -
StopUnit("sshd.service", "replace"):停止 SSH 服务 -
ListUnits():列出所有 systemd 管理的单元
-
📌 用途:你可以通过这个接口远程控制服务的启动、停止、重启等,非常适合系统管理工具或脚本。
📡 示例二:D-Bus 信号(NetworkManager)
服务名:org.freedesktop.NetworkManager
NetworkManager 提供网络管理功能,并通过 D-Bus 广播网络状态变化。
-
对象路径:
/org/freedesktop/NetworkManager -
接口名:
org.freedesktop.NetworkManager -
信号示例:
-
StateChanged(uint32 new_state):网络状态发生变化 -
DeviceAdded(object_path device):新设备连接 -
DeviceRemoved(object_path device):设备断开
-
📌 用途:桌面环境或后台服务可以监听这些信号,自动更新 UI 或触发网络相关操作。
🎧 示例三:D-Bus 信号(PulseAudio)
服务名:org.PulseAudio1
PulseAudio 是 Linux 上常用的音频服务器,它也通过 D-Bus 发送信号。
-
对象路径:
/org/pulseaudio/core1 -
接口名:
org.PulseAudio.Core1 -
信号示例:
-
NewSink(object_path sink):新音频输出设备连接 -
FallbackSinkChanged(object_path sink):默认输出设备改变
-
📌 用途:音量控制器或音频管理器可以监听这些信号,动态更新设备列表或音量状态。
可以用dbus-monitor来监控D-BUS上任何消息。 比如
pi@raspberrypi:~ $ dbus-monitor
signal time=1755152993.227039 sender=org.freedesktop.DBus -> destination=:1.37 serial=2 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameAcquired
string ":1.37"
signal time=1755152993.227217 sender=org.freedesktop.DBus -> destination=:1.37 serial=4 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameLost
string ":1.37"
method call time=1755152998.542688 sender=:1.38 -> destination=org.freedesktop.DBus serial=1 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=Hello
method return time=1755152998.542789 sender=org.freedesktop.DBus -> destination=:1.38 serial=1 reply_serial=1
string ":1.38"
signal time=1755152998.542871 sender=org.freedesktop.DBus -> destination=(null destination) serial=56 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameOwnerChanged
string ":1.38"
string ""
string ":1.38"
signal time=1755152998.543004 sender=org.freedesktop.DBus -> destination=:1.38 serial=2 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameAcquired
string ":1.38"
method call time=1755152998.543208 sender=:1.38 -> destination=org.example.HelloService serial=2 path=/org/example/HelloObject; interface=org.example.HelloInterface; member=SayHello
method return time=1755152998.589636 sender=:1.30 -> destination=:1.38 serial=8 reply_serial=2
string "Hello from C D-Bus Service!"
signal time=1755152998.593496 sender=org.freedesktop.DBus -> destination=:1.38 serial=3 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameLost
string ":1.38"
signal time=1755152998.593809 sender=org.freedesktop.DBus -> destination=(null destination) serial=57 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameOwnerChanged
string ":1.38"
string ":1.38"
string ""
signal time=1755152998.640193 sender=org.freedesktop.DBus -> destination=:1.30 serial=5 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameLost
string "org.example.HelloService"
signal time=1755152998.640317 sender=org.freedesktop.DBus -> destination=(null destination) serial=58 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameOwnerChanged
string "org.example.HelloService"
string ":1.30"
string ""
signal time=1755152998.640433 sender=org.freedesktop.DBus -> destination=:1.30 serial=6 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameLost
string ":1.30"
signal time=1755152998.640505 sender=org.freedesktop.DBus -> destination=(null destination) serial=59 path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameOwnerChanged
string ":1.30"
string ":1.30"
string ""
工具简介
| 工具 | 用途 |
|---|---|
dbus-send | 发送 D-Bus 方法调用或信号 |
dbus-monitor | 实时监听 D-Bus 消息(方法调用、信号) |
busctl(可选) | systemd 提供的 D-Bus 管理工具,支持 introspection |
🧪 示例一:调用 systemd 的 StartUnit 方法(启动 SSH 服务)
bash
dbus-send --system \
--dest=org.freedesktop.systemd1 \
--type=method_call \
--print-reply \
/org/freedesktop/systemd1 \
org.freedesktop.systemd1.Manager.StartUnit \
string:"ssh.service" \
string:"replace"
📌 说明:
-
--system表示使用系统总线 -
--print-reply显示返回结果 -
两个
string:参数分别是服务名和启动模式
📡 示例二:监听 NetworkManager 的信号
bash
dbus-monitor --system "type='signal',interface='org.freedesktop.NetworkManager'"
📌 说明:
-
监听系统总线上 NetworkManager 接口的所有信号
-
例如插入网线、连接 Wi-Fi 时会触发信号
📦 示例三:发送自定义信号(测试用)
bash
dbus-send --session \
--type=signal \
/com/example/MyService \
com.example.MyService.HelloSignal \
string:"Hello from CLI"
📌 说明:
-
--session表示使用会话总线 -
发送一个名为
HelloSignal的信号,带一个字符串参数
🔍 示例四:查看服务支持的方法(使用 busctl)
bash
busctl introspect --system org.freedesktop.systemd1 /org/freedesktop/systemd1
📌 说明:
-
显示 systemd 服务的所有接口、方法、信号、属性
-
非常适合探索未知服务的功能
🧪 示例五:监听所有 D-Bus 消息(调试用)
bash
dbus-monitor --system
或:
bash
dbus-monitor --session
📌 说明:
-
打印所有系统或会话总线上的消息
-
可用于调试或观察服务行为
-
dbus-send:发送 D-Bus 消息(方法调用或信号)📌 功能简介
-
发送 D-Bus 方法调用或信号
-
支持系统总线和会话总线
-
适合快速测试服务是否响应
-
🧪 常见用法
✅ 调用 systemd 的
StartUnit方法bash
dbus-send --system \ --dest=org.freedesktop.systemd1 \ --type=method_call \ --print-reply \ /org/freedesktop/systemd1 \ org.freedesktop.systemd1.Manager.StartUnit \ string:"ssh.service" \ string:"replace"✅ 发送自定义信号(测试用)
bash
dbus-send --session \ --type=signal \ /com/example/MyService \ com.example.MyService.HelloSignal \ string:"Hello from CLI"⚠️ 注意事项
-
不支持复杂数据结构(如数组、字典)
-
不支持自动 introspection(无法查询接口信息)
-
适合简单测试,不适合复杂交互
-
📡 二、
dbus-monitor:监听 D-Bus 消息(信号或方法调用)📌 功能简介
-
实时监听 D-Bus 总线上的消息
-
可过滤特定服务、接口、类型
-
适合调试和观察服务行为
-
🧪 常见用法
✅ 监听所有系统总线上的消息
bash
dbus-monitor --system✅ 监听 NetworkManager 的信号
bash
dbus-monitor --system "type='signal',interface='org.freedesktop.NetworkManager'"✅ 监听自定义服务的信号
bash
dbus-monitor --session "type='signal',interface='com.example.MyService'"⚠️ 注意事项
-
只能监听,不能发送消息
-
输出格式为原始 D-Bus 消息结构,不太友好
-
适合调试和事件观察
-
🧭 三、
busctl:高级 D-Bus 管理工具(由 systemd 提供)📌 功能简介
-
支持 introspection(查看接口、方法、信号)
-
支持调用方法、设置属性、监听信号
-
支持复杂参数类型(结构体、数组、字典)
-
更现代、更强大,推荐使用
-
busctl call --system \ org.freedesktop.systemd1 \ /org/freedesktop/systemd1 \ org.freedesktop.systemd1.Manager \ StartUnit \ s s "ssh.service" "replace"✅ 监听信号(如 NetworkManager)
bash
busctl monitor --system org.freedesktop.NetworkManager✅ 获取属性值(如 systemd 的版本)
bash
busctl get-property --system \ org.freedesktop.systemd1 \ /org/freedesktop/systemd1 \ org.freedesktop.systemd1.Manager \ Version⚠️ 注意事项
-
需要 systemd 支持(大多数现代 Linux 都有)
-
参数类型必须明确指定(如
s表示字符串) -
输出更清晰,适合脚本和自动化
下面来举一个更加简单的例子:
构建一个最基础的 D-Bus 服务和客户端,用 C 语言实现。目标是:
✅ 创建一个 D-Bus 服务,提供一个
SayHello()方法 ✅ 创建一个客户端,调用该方法并接收返回的字符串 ✅ 使用Makefile一键编译 ✅ 保证代码最小化、可运行、易理解
🧱 项目结构
Code
dbus_c_minimal/
├── Makefile
├── hello_service.c
└── hello_client.c
🛠️ 1. 服务端代码:hello_service.c
c
#include <dbus/dbus.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
DBusError err;
DBusConnection* conn;
DBusMessage* msg;
dbus_error_init(&err);
conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
dbus_bus_request_name(conn, "org.example.HelloService", DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
while (1) {
dbus_connection_read_write(conn, 0);
msg = dbus_connection_pop_message(conn);
if (msg == NULL) {
usleep(100000);
continue;
}
if (dbus_message_is_method_call(msg, "org.example.HelloInterface", "SayHello")) {
DBusMessage* reply = dbus_message_new_method_return(msg);
DBusMessageIter args;
const char* reply_text = "Hello from D-Bus C Service!";
dbus_message_iter_init_append(reply, &args);
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &reply_text);
dbus_connection_send(conn, reply, NULL);
dbus_message_unref(reply);
}
dbus_message_unref(msg);
}
return 0;
}
🧑💻 2. 客户端代码:hello_client.c
c
#include <dbus/dbus.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
DBusError err;
DBusConnection* conn;
DBusMessage* msg;
DBusMessageIter args;
DBusPendingCall* pending;
char* reply;
dbus_error_init(&err);
conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
msg = dbus_message_new_method_call("org.example.HelloService",
"/org/example/HelloObject",
"org.example.HelloInterface",
"SayHello");
dbus_connection_send_with_reply(conn, msg, &pending, -1);
dbus_connection_flush(conn);
dbus_message_unref(msg);
dbus_pending_call_block(pending);
msg = dbus_pending_call_steal_reply(pending);
dbus_pending_call_unref(pending);
if (dbus_message_iter_init(msg, &args) &&
dbus_message_iter_get_arg_type(&args) == DBUS_TYPE_STRING) {
dbus_message_iter_get_basic(&args, &reply);
printf("Client received: %s\n", reply);
}
dbus_message_unref(msg);
return 0;
}
🧰 3. Makefile(已修复 Tab)
makefile
CC = gcc
CFLAGS = -Wall -g $(shell pkg-config --cflags dbus-1)
LDFLAGS = $(shell pkg-config --libs dbus-1)
all: hello_service hello_client
hello_service: hello_service.c
$(CC) $(CFLAGS) -o hello_service hello_service.c $(LDFLAGS)
hello_client: hello_client.c
$(CC) $(CFLAGS) -o hello_client hello_client.c $(LDFLAGS)
clean:
rm -f hello_service hello_client
🚀 使用步骤
-
安装依赖(如未安装):
bash
sudo apt install libdbus-1-dev -
编译项目:
bash
make -
启动服务(终端 1):
bash
./hello_service -
启动客户端(终端 2):
bash
./hello_client
输出示例:
Code
Client received: Hello from D-Bus C Service!
假如你是从命令行来触发的话,可以这么做, (先跑起hello_service)
创建了一个 D-Bus 服务和客户端,现在我们来用命令行工具来测试它,验证它是否真的在 D-Bus 上注册并能响应请求。
🧭 你的服务信息(来自脚本)
| 项目 | 值 |
|---|---|
| 服务名 | org.example.HelloService |
| 对象路径 | /org/example/HelloObject |
| 接口名 | org.example.HelloInterface |
| 方法名 | SayHello |
🧪 一、使用 dbus-send 调用你的服务方法
bash
dbus-send --session \
--dest=org.example.HelloService \
--print-reply \
/org/example/HelloObject \
org.example.HelloInterface.SayHello
📌 说明:
-
--session:使用会话总线(你的服务是会话服务) -
--dest:服务名 -
/org/example/HelloObject:对象路径 -
org.example.HelloInterface.SayHello:方法名 -
--print-reply:打印返回值(你服务会返回一个字符串)
✅ 如果服务运行正常,你会看到类似输出:
Code
method return time=... sender=:1.XX -> destination=:1.YY serial=ZZ reply_serial=AA
string "Hello from C D-Bus Service!"
📡 二、使用 dbus-monitor 监听你的服务消息
bash
dbus-monitor --session "type='method_call',destination='org.example.HelloService'"
📌 说明:
-
监听所有发往你的服务的 D-Bus 方法调用
-
你可以看到客户端调用
SayHello的消息结构
📋 三、查看当前注册的 D-Bus 服务
bash
dbus-send --session --print-reply \
--dest=org.freedesktop.DBus \
/org/freedesktop/DBus \
org.freedesktop.DBus.ListNames
✅ 你应该能在输出中看到:
Code
string "org.example.HelloService"
🧠 总结
你现在可以:
-
用
dbus-send模拟客户端调用你的服务 -
用
dbus-monitor观察服务是否收到调用 -
用
ListNames验证服务是否成功注册
993

被折叠的 条评论
为什么被折叠?



