DBus Match API
概述
mc::dbus::match 和 mc::dbus::match_rule 用于创建和管理 DBus 消息匹配规则,实现消息过滤和信号监听功能。
类定义
namespace mc::dbus {
class match_rule;
class match;
}
Match Rule
match_rule 定义消息匹配规则。
创建匹配规则
构造函数
match_rule(DBus::Match::MessageType type,
const std::string_view& member,
const std::string_view& interface);
创建匹配规则。
参数:
type[in] - 消息类型member[in] - 成员名称interface[in] - 接口名称
new_signal
static match_rule new_signal(const std::string_view& member,
const std::string_view& interface);
创建信号匹配规则(便捷方法)。
参数:
member[in] - 信号名称interface[in] - 接口名称
返回值:
- 返回匹配规则对象
示例:
// 监听 NameOwnerChanged 信号
auto rule = mc::dbus::match_rule::new_signal(
"NameOwnerChanged",
"org.freedesktop.DBus"
);
配置匹配条件
匹配规则支持链式调用配置多个匹配条件。
with_interface
void with_interface(const std::string_view& interface);
设置匹配接口。
参数:
interface[in] - 接口名称
with_member
void with_member(const std::string_view& member);
设置匹配成员(方法名或信号名)。
参数:
member[in] - 成员名称
with_path
void with_path(const std::string_view& path);
设置匹配对象路径。
参数:
path[in] - 对象路径
with_path_namespace
void with_path_namespace(const std::string_view& path_namespace);
设置匹配路径命名空间。
参数:
path_namespace[in] - 路径命名空间
约束:
- 匹配该命名空间下的所有路径
示例:
// 匹配 /com/example/ 下的所有对象
rule.with_path_namespace("/com/example/");
with_sender
void with_sender(const std::string_view& sender);
设置匹配发送者。
参数:
sender[in] - 发送者名称
with_type
void with_type(DBus::Match::MessageType type);
设置匹配消息类型。
参数:
type[in] - 消息类型
with_destination
void with_destination(const std::string_view& destination);
设置匹配目标。
参数:
destination[in] - 目标服务名称
其他方法
clone
match_rule clone() const;
克隆匹配规则。
返回值:
- 返回克隆的匹配规则对象
as_string
std::string as_string() const;
将匹配规则转换为字符串。
返回值:
- 返回匹配规则的字符串表示
示例:
auto rule = mc::dbus::match_rule::new_signal("NameOwnerChanged",
"org.freedesktop.DBus");
std::cout << "匹配规则: " << rule.as_string() << std::endl;
// 输出: type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'
Match
match 用于管理多个匹配规则并分发匹配的消息。
构造函数
match();
创建匹配对象。
添加和移除规则
add_rule
void add_rule(match_rule& rule, match_cb_t&& cb, uint64_t id);
添加匹配规则。
参数:
rule[in] - 匹配规则cb[in] - 匹配成功时的回调函数id[in] - 规则的唯一标识符
回调函数类型:
using match_cb_t = std::function<void(mc::dbus::message&)>;
示例:
mc::dbus::match matcher;
auto rule = mc::dbus::match_rule::new_signal("StatusChanged",
"com.example.Interface");
matcher.add_rule(rule, [](mc::dbus::message& msg) {
std::cout << "收到状态变更信号" << std::endl;
std::string status;
msg.reader() >> status;
std::cout << "新状态: " << status << std::endl;
}, 1);
remove_rule
void remove_rule(uint64_t id);
移除匹配规则。
参数:
id[in] - 规则的唯一标识符
消息匹配
run_msg
bool run_msg(DBusMessage* msg);
运行消息匹配,执行匹配的回调。
参数:
msg[in] - DBus消息
返回值:
- 匹配成功并执行回调返回 true,否则返回 false
test_match
bool test_match(DBusMessage* msg);
测试消息是否匹配(不执行回调)。
参数:
msg[in] - DBus消息
返回值:
- 匹配返回 true,否则返回 false
使用示例
监听信号
#include <mc/dbus/connection.h>
#include <mc/dbus/match.h>
// 创建连接
mc::io_context executor(1);
auto conn = mc::dbus::connection::open_system_bus(executor);
conn.start();
// 创建信号匹配规则
auto rule = mc::dbus::match_rule::new_signal(
"NameOwnerChanged",
"org.freedesktop.DBus"
);
// 添加匹配规则
conn.add_match(rule, [](mc::dbus::message& msg) {
std::string name, old_owner, new_owner;
msg.reader() >> name >> old_owner >> new_owner;
std::cout << "服务 " << name << " 所有者变更" << std::endl;
std::cout << "旧所有者: " << old_owner << std::endl;
std::cout << "新所有者: " << new_owner << std::endl;
}, 1);
// 运行事件循环
executor.run();
多条件匹配
// 创建复杂匹配规则
auto rule = mc::dbus::match_rule::new_signal("PropertyChanged",
"com.example.Interface");
// 添加多个条件
rule.with_path("/com/example/Object");
rule.with_sender("com.example.Service");
conn.add_match(rule, [](mc::dbus::message& msg) {
// 处理属性变更信号
std::string property;
mc::variant value;
msg.reader() >> property >> value;
std::cout << "属性 " << property << " 变更为: "
<< value.as<std::string>() << std::endl;
}, 2);
路径命名空间匹配
// 匹配特定命名空间下的所有信号
auto rule = mc::dbus::match_rule::new_signal("StateChanged",
"com.example.Device");
rule.with_path_namespace("/com/example/devices/");
conn.add_match(rule, [](mc::dbus::message& msg) {
auto path = msg.get_path();
std::cout << "设备 " << path << " 状态变更" << std::endl;
}, 3);
管理多个匹配规则
class signal_manager {
public:
signal_manager(mc::dbus::connection& conn) : m_conn(conn) {}
void add_status_monitor(uint64_t id) {
auto rule = mc::dbus::match_rule::new_signal(
"StatusChanged",
"com.example.Service"
);
m_conn.add_match(rule, [this](mc::dbus::message& msg) {
handle_status_change(msg);
}, id);
m_rule_ids.push_back(id);
}
void add_error_monitor(uint64_t id) {
auto rule = mc::dbus::match_rule::new_signal(
"ErrorOccurred",
"com.example.Service"
);
m_conn.add_match(rule, [this](mc::dbus::message& msg) {
handle_error(msg);
}, id);
m_rule_ids.push_back(id);
}
void remove_all() {
for (auto id : m_rule_ids) {
m_conn.remove_match(id);
}
m_rule_ids.clear();
}
private:
void handle_status_change(mc::dbus::message& msg) {
// 处理状态变更
}
void handle_error(mc::dbus::message& msg) {
// 处理错误
}
mc::dbus::connection& m_conn;
std::vector<uint64_t> m_rule_ids;
};
动态添加和移除规则
class dynamic_listener {
public:
dynamic_listener(mc::dbus::connection& conn)
: m_conn(conn), m_next_id(1) {}
uint64_t subscribe(const std::string& signal_name,
const std::string& interface,
std::function<void(mc::dbus::message&)> callback) {
auto rule = mc::dbus::match_rule::new_signal(signal_name, interface);
uint64_t id = m_next_id++;
m_conn.add_match(rule, std::move(callback), id);
return id;
}
void unsubscribe(uint64_t id) {
m_conn.remove_match(id);
}
private:
mc::dbus::connection& m_conn;
uint64_t m_next_id;
};
// 使用
dynamic_listener listener(conn);
// 订阅
auto id1 = listener.subscribe("StatusChanged", "com.example.Service",
[](mc::dbus::message& msg) {
std::cout << "状态变更" << std::endl;
});
auto id2 = listener.subscribe("ValueChanged", "com.example.Sensor",
[](mc::dbus::message& msg) {
std::cout << "值变更" << std::endl;
});
// 取消订阅
listener.unsubscribe(id1);
Service 中的匹配规则
service::add_match
namespace mc::engine {
class service {
public:
uint64_t add_match(mc::dbus::match_rule& rule, mc::dbus::match_cb_t&& cb);
void remove_match(uint64_t id);
};
}
在服务对象中添加匹配规则,同时支持 DBus 和共享内存匹配。
参数:
rule[in] - 匹配规则对象(会被克隆,原对象可继续使用)cb[in] - 回调函数,当匹配的消息到达时被调用
返回值:
uint64_t- 匹配规则 ID,用于后续移除规则
功能说明:
- 同时添加 DBus 匹配规则和共享内存匹配规则
- 自动生成唯一的规则 ID
- 规则对象会被克隆,避免与 harbor 的规则冲突
- 回调函数会在匹配的消息到达时被调用
实现细节:
- 首先在共享内存树(shm_tree)中添加匹配规则
- 然后克隆规则对象并在 DBus 连接中添加匹配规则
- 规则克隆是必要的,因为 harbor 和服务都会调用
add_rule,如果使用同一个规则对象,服务调用rule->set_slot会导致 harbor 的 slot 被析构
示例:
#include <mc/engine/service.h>
#include <mc/dbus/match.h>
// 创建服务
auto svc = std::make_shared<mc::engine::service>("com.example.Service");
svc->init({});
// 创建匹配规则
auto rule = mc::dbus::match_rule::new_signal(
"StatusChanged",
"com.example.Interface"
);
rule.with_path("/com/example/Object");
// 添加匹配规则
uint64_t match_id = svc->add_match(rule, [](mc::dbus::message& msg) {
std::string status;
msg.reader() >> status;
std::cout << "状态变更: " << status << std::endl;
});
// 移除匹配规则
svc->remove_match(match_id);
与 connection::add_match 的区别:
| 特性 | connection::add_match |
service::add_match |
|---|---|---|
| 匹配范围 | 仅 DBus 匹配 | DBus + 共享内存匹配 |
| 规则克隆 | 不需要 | 自动克隆 |
| ID 生成 | 需要手动指定 | 自动生成 |
| 适用场景 | 普通客户端 | 服务端应用 |
注意事项:
- 规则对象会被克隆,修改原规则对象不会影响已添加的规则
- 回调函数会在 IO 线程中执行,避免长时间阻塞
- 服务销毁时会自动清理所有匹配规则
- 规则 ID 是全局唯一的,由静态计数器生成
注意事项
- 规则ID唯一性:确保每个规则的ID唯一,避免冲突
- 及时移除:不再需要时及时移除匹配规则,避免内存泄漏
- 回调线程:回调函数在 IO 线程中执行,避免长时间阻塞
- 规则字符串:DBus 匹配规则有特定语法,使用 API 构建避免错误
- 权限检查:某些信号可能需要权限才能监听
- 规则克隆:在
service::add_match中,规则会被自动克隆,原规则对象可继续使用
相关接口
- connection - 连接对象
- message - 消息对象
- signal - 信号发射
- shm - 共享内存通信