文章目录
- 本地FastDDS+远端MQTT转发(多主机数据隔离)架构设计与落地
-
- 一、架构核心设计(贴合你的多主机/Qt+C++场景)
-
- [1. 整体架构图(文字版)](#1. 整体架构图(文字版))
- [2. 核心模块职责](#2. 核心模块职责)
- 二、数据隔离的双层实现(核心需求落地)
-
- [1. 本地层:FastDDS Domain ID 物理隔离](#1. 本地层:FastDDS Domain ID 物理隔离)
- [2. 远端层:MQTT主题+ACL 逻辑隔离](#2. 远端层:MQTT主题+ACL 逻辑隔离)
-
- (1)MQTT主题命名规则(统一格式,强制隔离)
- [(2)MQTT Broker ACL权限(强化隔离)](#(2)MQTT Broker ACL权限(强化隔离))
- 三、架构优缺点
-
- [1. 核心优势](#1. 核心优势)
- [2. 潜在劣势与解决方案](#2. 潜在劣势与解决方案)
- 四、Qt+C++落地实现要点(核心代码框架)
-
- [1. 中转站核心代码(FastDDS接收+MQTT转发)](#1. 中转站核心代码(FastDDS接收+MQTT转发))
- [2. 本地EXE代码(仅需FastDDS,无需关心MQTT)](#2. 本地EXE代码(仅需FastDDS,无需关心MQTT))
- [3. 配置文件(config.ini,跨主机仅需修改此文件)](#3. 配置文件(config.ini,跨主机仅需修改此文件))
- 五、最终建议
-
- [1. 架构选型结论](#1. 架构选型结论)
- [2. 落地优先级](#2. 落地优先级)
- [3. 替代方案对比(仅作参考)](#3. 替代方案对比(仅作参考))
本地FastDDS+远端MQTT转发(多主机数据隔离)架构设计与落地
一、架构核心设计(贴合你的多主机/Qt+C++场景)
该架构的核心是**"单主机FastDDS域隔离 + 中转站统一转发 + MQTT主题/ACL远端隔离"**,每台主机部署一个"FastDDS-MQTT中转站",作为本地FastDDS和远端MQTT的唯一桥梁,既保留FastDDS本地自动配置的优势,又通过MQTT实现跨主机/远端通信,同时保障多主机数据隔离。
1. 整体架构图(文字版)
text
┌────────────────────────────────────────────── 主机A ──────────────────────────────────────────────┐
│ ┌─────────┐ ┌─────────┐ ┌──────────────────────────────────────────────┐ │
│ │本地EXE 1│ │本地EXE 2│ │ FastDDS-MQTT 中转站 │ │
│ │(FastDDS)│◄──►│(FastDDS)│◄──►│ [FastDDS模块] [MQTT模块] [隔离管控] │◄─────┐ │
│ └─────────┘ └─────────┘ └──────────────────────────────────────────────┘ │ │
│ ▲ │ │
│ │(本地 FastDDS,Domain ID = 100) │ │
└────────────────────────────────────┴────────────────────────────────────────────────┘ │
│
┌────────────────────────────────────────────── 主机B ──────────────────────────────────────────────┐
│ ┌─────────┐ ┌─────────┐ ┌──────────────────────────────────────────────┐ │
│ │本地EXE 1│ │本地EXE 2│ │ FastDDS-MQTT 中转站 │ │
│ │(FastDDS)│◄──►│(FastDDS)│◄──►│ [FastDDS模块] [MQTT模块] [隔离管控] │◄─────┐ │
│ └─────────┘ └─────────┘ └──────────────────────────────────────────────┘ │ │
│ ▲ │ │
│ │(本地 FastDDS,Domain ID = 101) │ │
└────────────────────────────────────┴────────────────────────────────────────────────┘ │
│
▼ ▼
┌───────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 远端 MQTT Broker(EMQ X / 阿里云 IoT) │
│ (主题隔离 + ACL 权限,实现多主机数据隔离) │
└───────────────────────────────────────────────────────────────────────────────────────────────────┘
2. 核心模块职责
| 模块 | 核心职责 |
|---|---|
| 本地EXE(FastDDS) | 仅接入本机专属FastDDS域,发布/订阅数据(无需关心MQTT),享受FastDDS自动发现/配置的优势; |
| 主机内FastDDS域 | 每台主机分配唯一Domain ID(如主机A=100,主机B=101),本地FastDDS仅发现同域节点,实现本地数据物理隔离; |
| FastDDS-MQTT中转站 | 1. 本机FastDDS域的"超级节点":订阅本地所有FastDDS Topic,接收所有EXE数据; 2. 数据转换:将FastDDS的CDR格式转为MQTT可传输的ProtoBuf/JSON; 3. MQTT转发:按"主机标识+Topic"规则发布到远端Broker; 4. 反向转发:接收远端MQTT数据,转换为FastDDS格式,发布到本机域; 5. 隔离管控:严格按权限订阅/发布MQTT主题,禁止跨主机越权; |
| 远端MQTT Broker | 1. 主题隔离:按"主机标识"划分MQTT主题空间; 2. ACL权限:限制每个中转站仅能访问自身主机的主题; |
二、数据隔离的双层实现(核心需求落地)
多主机数据隔离需从"本地物理隔离"和"远端逻辑隔离"两层入手,缺一不可:
1. 本地层:FastDDS Domain ID 物理隔离
- 核心逻辑:FastDDS的Domain ID是节点分组的核心标识,不同Domain ID的节点无法互相发现、通信,实现"本机数据不跨域";
- 落地配置 :
- 为每台主机分配唯一的Domain ID(范围0-232,避免冲突),写入中转站的配置文件(如
domain_id=100); - 本地所有EXE和中转站均使用该Domain ID创建FastDDS参与者,跨主机的FastDDS数据完全隔离,即使网络互通也无法访问;
- 中转站是本机域内唯一能与MQTT交互的节点,本地EXE无MQTT权限,杜绝EXE直接访问远端数据。
- 为每台主机分配唯一的Domain ID(范围0-232,避免冲突),写入中转站的配置文件(如
2. 远端层:MQTT主题+ACL 逻辑隔离
(1)MQTT主题命名规则(统一格式,强制隔离)
定义全局唯一的主题格式,将"主机标识"作为主题前缀,确保不同主机的数据不会混流:
/host/{主机唯一标识}/{数据类型}/{FastDDS Topic名}
- 示例:
- 主机A(标识
device001)的北斗数据:/host/device001/sensor/BeidouData; - 主机B(标识
device002)的USBL数据:/host/device002/sensor/USBLData;
- 主机A(标识
- 中转站自动拼接规则:读取本机配置的
host_id,将本地FastDDS Topic转换为上述MQTT主题,无需手动修改代码。
(2)MQTT Broker ACL权限(强化隔离)
在MQTT Broker(推荐EMQ X)中配置ACL规则,限制每个中转站的MQTT客户端仅能访问自身主机的主题:
# EMQ X ACL配置示例
allow device001 publish /host/device001/#
allow device001 subscribe /host/device001/#
allow device002 publish /host/device002/#
allow device002 subscribe /host/device002/#
deny all publish #
deny all subscribe #
- 效果:主机A的中转站只能发布/订阅
/host/device001/下的主题,无法访问主机B的主题,即使知道主题名也会被Broker拒绝。
三、架构优缺点
1. 核心优势
| 优势维度 | 具体价值 |
|---|---|
| 本地通信体验 | 完全复用FastDDS的自动发现/配置/序列化,本地EXE仅需订阅Topic即可通信,无需手动配置地址/序列化; |
| 数据隔离安全性 | 双层隔离(Domain ID物理隔离+MQTT主题/ACL逻辑隔离),多主机数据完全隔离,避免越权访问; |
| 远端通信适配性 | MQTT穿透性强(跨网段/公网/防火墙),部署成本远低于FastDDS的跨网段DS服务器; |
| Qt+C++适配性 | FastDDS和Qt MQTT模块(Qt5.10+原生支持)均可集成到Qt项目,跨平台(Win/Linux/macOS)编译; |
| 灵活性 | 本地保留FastDDS的实时性(5-10ms),远端用MQTT降低部署复杂度,兼顾实时性和易用性; |
2. 潜在劣势与解决方案
| 劣势 | 解决方案 |
|---|---|
| 中转站单点风险 | 1. 中转站进程加入心跳检测(本地EXE监控,异常则自动重启); 2. 关键主机可部署双中转站,MQTT Broker做主备切换; |
| 数据转换成本 | 封装通用转换模块:FastDDS IDL生成的类 ↔ ProtoBuf/JSON,一次性封装后所有主机复用; |
| MQTT延迟较高(100-200ms) | 1. MQTT Broker就近部署(如与主机同区域); 2. 配置MQTT QoS=0(实时性优先); 3. 高频数据压缩后传输; |
| 配置项较多 | 统一配置文件管理:将Domain ID、host_id、MQTT Broker地址等写入config.ini,所有模块读取配置,无需修改代码; |
四、Qt+C++落地实现要点(核心代码框架)
1. 中转站核心代码(FastDDS接收+MQTT转发)
cpp
#include <QCoreApplication>
#include <QSettings>
#include <QMqttClient>
#include "fastdds/dds/domain/DomainParticipantFactory.hpp"
#include "UnifiedDataPubSubTypes.h" // FastDDS IDL生成的类
// 全局配置(从config.ini读取)
QSettings settings("config.ini", QSettings::IniFormat);
int domainId = settings.value("fastdds/domain_id").toInt();
QString hostId = settings.value("mqtt/host_id").toString();
QString mqttBroker = settings.value("mqtt/broker").toString();
int mqttPort = settings.value("mqtt/port").toInt();
// FastDDS数据监听类
class FastDDSListener : public DataReaderListener {
public:
void on_data_available(DataReader* reader) override {
UnifiedData data;
SampleInfo info;
if (reader->take_next_sample(&data, &info) == RETCODE_OK && info.valid_data) {
// 1. FastDDS数据转换为ProtoBuf(或JSON)
std::string serializedData;
data.SerializeToString(&serializedData);
// 2. 拼接MQTT主题(/host/device001/sensor/UnifiedData)
QString mqttTopic = QString("/host/%1/sensor/%2").arg(hostId).arg(data.topic_name());
// 3. MQTT发布
QMqttClient* client = qobject_cast<QMqttClient*>(parent());
client->publish(mqttTopic, QByteArray(serializedData.c_str(), serializedData.size()));
}
}
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
// ========== 1. 初始化FastDDS(本机Domain ID) ==========
DomainParticipant* participant = DomainParticipantFactory::get_instance()->create_participant(
domainId, PARTICIPANT_QOS_DEFAULT);
UnifiedDataPubSubType type;
participant->register_type(&type);
Topic* topic = participant->create_topic("UnifiedData", type.get_type_name(), TOPIC_QOS_DEFAULT);
Subscriber* subscriber = participant->create_subscriber(SUBSCRIBER_QOS_DEFAULT);
FastDDSListener listener;
DataReader* reader = subscriber->create_datareader(topic, DATAREADER_QOS_DEFAULT, &listener);
// ========== 2. 初始化MQTT客户端 ==========
QMqttClient mqttClient;
mqttClient.setHostname(mqttBroker);
mqttClient.setPort(mqttPort);
mqttClient.setClientId(hostId); // MQTT客户端ID=主机标识,便于Broker ACL管控
mqttClient.connectToHost();
// 绑定FastDDS监听器的父对象为MQTT客户端,便于转发
listener.setParent(&mqttClient);
// ========== 3. MQTT接收远端数据,转发到本地FastDDS ==========
connect(&mqttClient, &QMqttClient::messageReceived, [&](const QByteArray& msg, const QMqttTopicName& topic) {
// 仅处理本机主题(避免跨主机数据)
if (!topic.name().startsWith(QString("/host/%1/").arg(hostId))) return;
// MQTT数据转换为FastDDS格式,发布到本机域
UnifiedData data;
data.ParseFromArray(msg.data(), msg.size());
DataWriter* writer = participant->create_datawriter(topic, DATAWRITER_QOS_DEFAULT);
writer->write(&data);
});
// 订阅本机MQTT主题
mqttClient.subscribe(QMqttTopicFilter(QString("/host/%1/#").arg(hostId)));
return a.exec();
}
2. 本地EXE代码(仅需FastDDS,无需关心MQTT)
cpp
#include <QCoreApplication>
#include <QSettings>
#include "fastdds/dds/domain/DomainParticipantFactory.hpp"
#include "UnifiedDataPubSubTypes.h"
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
// 读取本机Domain ID(与中转站一致)
QSettings settings("config.ini", QSettings::IniFormat);
int domainId = settings.value("fastdds/domain_id").toInt();
// FastDDS初始化(仅需3步,自动发现中转站)
DomainParticipant* participant = DomainParticipantFactory::get_instance()->create_participant(domainId, PARTICIPANT_QOS_DEFAULT);
UnifiedDataPubSubType type;
participant->register_type(&type);
Topic* topic = participant->create_topic("UnifiedData", type.get_type_name(), TOPIC_QOS_DEFAULT);
// 发布数据(自动发现本机域内的订阅者,无需指定地址)
Publisher* publisher = participant->create_publisher(PUBLISHER_QOS_DEFAULT);
DataWriter* writer = publisher->create_datawriter(topic, DATAWRITER_QOS_DEFAULT);
UnifiedData data;
data.set_topic_name("UnifiedData");
data.set_content("本地EXE的北斗数据");
writer->write(&data);
return a.exec();
}
3. 配置文件(config.ini,跨主机仅需修改此文件)
ini
[fastdds]
domain_id = 100 # 主机A=100,主机B=101,以此类推
[mqtt]
host_id = device001 # 主机唯一标识
broker = 47.96.38.26 # MQTT Broker公网IP
port = 1883
五、最终建议
1. 架构选型结论
该架构(本地FastDDS+远端MQTT+双层隔离)是你场景的最优解:
- 满足"本地EXE仅订阅即可通信":复用FastDDS自动配置/发现的优势,降低本地EXE开发成本;
- 满足"多主机数据隔离":Domain ID物理隔离+MQTT主题/ACL逻辑隔离,安全性可控;
- 跨平台适配:FastDDS和Qt MQTT均支持Win/Linux/macOS,配置文件统一管理,部署灵活;
- 成本平衡:本地实时性(FastDDS)+ 远端易用性(MQTT),比纯FastDDS跨网段部署成本低,比纯MQTT本地通信实时性高。
2. 落地优先级
- 先完成单主机验证:部署中转站+本地EXE,测试FastDDS本地通信+MQTT转发;
- 配置Broker ACL规则,验证多主机数据隔离;
- 封装通用转换模块(FastDDS↔ProtoBuf),所有主机复用;
- 增加中转站容灾、数据压缩、心跳检测等优化。
3. 替代方案对比(仅作参考)
| 方案 | 隔离性 | 本地体验 | 远端部署成本 | 实时性 | 适配性 |
|---|---|---|---|---|---|
| 本地FastDDS+远端MQTT | 高 | 优 | 低 | 中高 | 优 |
| 纯FastDDS(跨网段) | 高 | 优 | 高(需DS集群) | 高 | 中 |
| 纯MQTT(本地+远端) | 中 | 差(手动配置) | 低 | 中 | 中 |
综上,该架构完美适配你的核心需求:本地FastDDS简化配置、远端MQTT降低部署成本、双层隔离保障多主机数据安全,且完全兼容Qt+C++跨平台开发体系。