以下是关于 D-Bus(QDBus)在实际应用中的几个典型示例,涵盖服务端/客户端交互、信号监听和异步调用等场景:
示例 1:远程方法调用(RPC)
场景:控制媒体播放器的播放/暂停功能
实现步骤:
-
定义 D-Bus 接口文件 (
com.example.MediaPlayer.xml
):<node> <interface name="com.example.MediaPlayer"> <method name="PlayPause"/> <method name="SetVolume"> <arg type="i" name="volume" direction="in"/> </method> <property type="i" name="CurrentVolume" access="read"/> </interface> </node>
-
服务端实现:
#include <QDBusConnection> #include <QDBusInterface> class MediaPlayer : public QObject { Q_OBJECT public: explicit MediaPlayer(QObject *parent = nullptr) : QObject(parent) { QDBusConnection::sessionBus().registerObject("/MediaPlayer", this); QDBusConnection::sessionBus().registerService("com.example.MediaPlayer"); } public slots: void PlayPause() { // 实现播放/暂停逻辑 qDebug() << "Play/Pause toggled"; } void SetVolume(int volume) { // 设置音量 qDebug() << "Volume set to" << volume; } int CurrentVolume() const { return 50; // 返回当前音量 } }; // 注册服务 int main() { MediaPlayer player; return QApplication::exec(); }
-
客户端调用:
QDBusInterface iface("com.example.MediaPlayer", "/MediaPlayer", "com.example.MediaPlayer", QDBusConnection::sessionBus()); // 调用 PlayPause 方法 iface.call("PlayPause"); // 调用 SetVolume 方法(同步) QDBusReply<void> reply = iface.call("SetVolume", 80); if (!reply.isValid()) { qWarning() << "Error:" << reply.error().message(); } // 读取属性(异步) QDBusPendingReply<int> volumeReply = iface.property("CurrentVolume").asVariant().value<QDBusPendingReply<int>>(); volumeReply.waitForFinished(); if (volumeReply.isError()) { qWarning() << "Error reading volume"; } else { qDebug() << "Current Volume:" << volumeReply.value(); }
示例 2:信号监听(Event Handling)
场景:监听系统电源状态变化
实现步骤:
-
服务端发送信号:
class PowerManager : public QObject { Q_OBJECT public: explicit PowerManager(QObject *parent = nullptr) : QObject(parent) { QDBusConnection::systemBus().registerObject("/PowerManager", this); QDBusConnection::systemBus().registerService("org.freedesktop.PowerManagement"); } signals: void BatteryLow(int percentage); }; // 触发信号(例如电量低于20%) void PowerManager::checkBattery() { if (batteryLevel < 20) { emit BatteryLow(batteryLevel); } }
-
客户端监听信号:
QDBusInterface powerIface("org.freedesktop.PowerManagement", "/PowerManager", "org.freedesktop.PowerManagement", QDBusConnection::systemBus()); // 连接信号到槽函数 QObject::connect(&powerIface, &QDBusInterface::BatteryLow, [](int percentage) { qDebug() << "Battery low!" << percentage << "% remaining"; // 触发省电模式 });
示例 3:异步方法调用
场景:非阻塞式调用远程服务
实现步骤:
// 客户端发起异步调用
QDBusInterface iface("com.example.Service", "/Service", "com.example.Service",
QDBusConnection::sessionBus());
QDBusPendingReply<QString> reply = iface.asyncCall("LongRunningTask", "input_data");
// 连接完成信号
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [](QDBusPendingCallWatcher *w) {
QDBusPendingReply<QString> reply = *w;
if (reply.isError()) {
qWarning() << "Error:" << reply.error().message();
} else {
qDebug() << "Result:" << reply.value();
}
w->deleteLater();
});
示例 4:服务激活(Auto-Start)
场景:通过 D-Bus 激活未运行的服务
实现步骤:
-
服务端注册激活策略(在
.desktop
文件中):[Desktop Entry] Name=MyService Exec=/path/to/myservice Type=DBus BusName=com.example.MyService
-
客户端调用服务:
QDBusInterface iface("com.example.MyService", "/MyService", "com.example.MyService", QDBusConnection::sessionBus()); // 如果服务未运行,D-Bus 会自动启动它
关键注意事项:
- 权限管理:系统级 D-Bus(
systemBus
)需要配置策略文件(/etc/dbus-1/system.d/
)。 - 线程安全:确保 D-Bus 操作在正确的线程上下文中执行。
- 错误处理:始终检查
QDBusReply
和QDBusError
。 - 性能优化:避免频繁的同步调用,优先使用异步模式。
通过这些示例,您可以快速构建基于 D-Bus 的跨进程通信系统,适用于桌面应用、系统服务或物联网设备控制等场景。