eProsima Fast DDS 中间件入门指南:高性能实时分布式通信利器

eProsima Fast DDS 中间件入门指南:高性能实时分布式通信利器
Fast DDS 是一个高性能中间件,使应用程序能够使用发布者-订阅者模式进行通信。它实现了 RTPS(实时发布-订阅)协议,允许通过网络进行可靠的数据交换。可以将其视为一个消息系统,应用程序可以向主题发布数据,其他应用程序可以订阅这些主题以接收数据。

前言

Fast DDS 是 ROS 2(机器人操作系统)的默认中间件,使其成为机器人和实时系统的可靠选择。在工业自动化、自动驾驶及机器人开发(如 ROS 2)领域,eProsima Fast DDS 已成为主流的通信中间件。本文从原理、对比到实战代码,带你深度入门这一高性能中间件。

1. 什么是 Fast DDS?

Fast DDS(前称 Fast RTPS)是 eProsima 开发的开源分布式通信框架,完整实现了 OMG 的 DDS(Data Distribution Service)标准。其核心协议是 RTPS (Real-Time Publish-Subscribe)。DDS 采用 “以数据为中心” 模型,开发者只需关注数据交换,无需处理网络拓扑和 Socket 编程。


eProsima Fast DDS GitHub 项目地址https://github.com/eProsima/Fast-DDS

2. 核心原理与架构

在这里插入图片描述
2.1 去中心化的 P2P 架构
  • 自动发现机制:节点通过 UDP 多播自动发现局域网内其他节点,交换端口信息建立连接。
  • 点对点传输:数据直接在节点间传输(无中转),实现微秒级延迟。
2.2 通信分层模型
层级作用
Domain逻辑隔离空间(相同 Domain ID 才能通信)
Participant代表应用在 DDS 域中的身份容器
Topic数据标签(如 Axis_Status
DataWriter/Reader实际执行数据读写的对象
在这里插入图片描述
2.3 相关概念介绍

DDS为以数据为中心的分布式系统提供了强大、灵活且高效的中间件解决方案。其核心概念——DomainParticipants、Publishers、Subscribers、Topics、DataWriters和DataReaders——协同工作,创建了解耦、可扩展的通信架构。QoS框架增加了另一层控制,允许开发人员微调通信行为以满足特定的应用需求。

Fast DDS通过高级DDS API和底层RTPS协议访问将这些功能带给C++开发人员,使其适用于从简单数据交换到复杂实时分布式系统的广泛应用。

2.3.1 数据分发服务(DDS)

数据分发服务(DDS)是一种以数据为中心的连接中间件协议和API标准,旨在实现发布者与订阅者之间可扩展、实时、可靠、高性能且互操作的数据交换。

Fast DDS是由eProsima开发的C++实现,提供了高级DDS API和底层RTPS(实时发布-订阅)协议访问。

DDS基于发布-订阅模型运行,该模型将数据生产者(发布者)与数据消费者(订阅者)解耦。这种架构实现了灵活且可扩展的通信模式,非常适合分布式系统。

DDS的一个关键优势是其自动发现机制。当创建新的DataWriter或DataReader时,DDS会自动检测它并与兼容的端点建立通信,而无需应用程序进行任何配置或干预。作为该标准的实现,Fast DDS已被包括ROS 2(机器人操作系统2)在内的主要项目采用作为其默认中间件,证明了其适用于复杂的实时分布式系统。

2.3.2 DomainParticipant

是DDS中的核心实体,充当所有其他DDS实体的容器。它表示应用程序在DDS域中的参与,域是发生通信的逻辑网络分区。可以将DomainParticipant视为应用程序进入DDS世界的网关。

每个DomainParticipant在其域内具有唯一标识,可以创建发布者、订阅者和主题。域之间相互隔离,意味着通信仅发生在同一域的参与者之间。

// 使用默认QoS设置创建DomainParticipant DomainParticipant* participant =DomainParticipantFactory::get_instance()->create_participant(0, PARTICIPANT_QOS_DEFAULT);

2.3.3 Publishers和Subscribers

是DDS中数据交换的主要通道。Publisher负责发送数据,而Subscriber接收数据。两者都在DomainParticipant内创建,可以管理多个数据流。

Publisher充当DataWriters的工厂,DataWriters是将数据发布到特定主题的实际对象。类似地,Subscriber创建从主题接收数据的DataReaders。

// 在参与者中创建Publisher Publisher* publisher = participant->create_publisher(PUBLISHER_QOS_DEFAULT);// 在参与者中创建Subscriber Subscriber* subscriber = participant->create_subscriber(SUBSCRIBER_QOS_DEFAULT);

2.3.4 DataWriter和DataReader

实际的数据生产者和消费者。

虽然Publishers和Subscribers管理通信通道,但DataWriters和DataReaders是处理数据传输和接收的实际对象。

DataWriter由Publisher为特定Topic创建,负责发布该主题数据类型的数据样本。类似地,DataReader由Subscriber为特定Topic创建,接收该主题数据类型的数据样本。

// 为ChatTopic创建DataWriter DataWriter* writer = publisher->create_datawriter(topic, DATAWRITER_QOS_DEFAULT);// 为ChatTopic创建DataReader DataReader* reader = subscriber->create_datareader(topic, DATAREADER_QOS_DEFAULT);

这种分层架构允许对数据通信进行细粒度控制。您可以为同一主题拥有具有不同QoS设置的多个DataWriters,或具有不同过滤条件的多个DataReaders。

2.4 传输层优化
  • UDP/TCP 支持:默认 UDP,复杂网络下支持 TCP。
  • 共享内存 (SHM):同机进程通过内存映射交换数据,绕过网络协议栈。
  • 零拷贝 (Zero-copy):避免大数据(如视频流)的内存多次拷贝。

3. 技术对比:Fast DDS vs. MQTT vs. ZeroMQ

特性Fast DDSMQTTZeroMQ
设计哲学以数据为中心,强实时控制以消息为中心通信原语库
网络模型去中心化 (P2P)中心化 (Broker)灵活 (P2P/Broker)
发现机制自动发现(无需配置 IP)需指定服务器 IP需手动指定 IP
QoS 支持丰富(23种策略)简单(QoS 0/1/2)需手动实现
典型延迟微秒级 (μs)毫秒级 (ms)微秒级 (μs)
适用场景机器人控制、自动驾驶智能家居、云端监控分布式计算
对比结论:需确定性低延迟 + 自动发现 → Fast DDS跨互联网 + 海量设备 → MQTT自定义底层通信逻辑 → ZeroMQ

4. 核心概念区分

4.1 静态代码生成 (IDL) vs. 动态类型
  • fastddsgen (IDL):通过 .idl 文件生成 C++ 类(编译时类型安全,性能最优)。
  • 动态类型:运行时构建数据结构(适合插件系统,性能略低)。
4.2 发现机制
  • PDP:发现网络中的参与者(Participant)。
  • EDP:在参与者间匹配主题的发布者/订阅者。
4.3 QoS 策略(核心特性)
策略作用
ReliabilityBEST_EFFORT(可丢包)或 RELIABLE(必达)
History缓存最近 N 条数据
Durability新订阅者是否接收历史数据

5. 快速上手:从代码到运行

5.1 安装 Fast DDS
# Ubuntu 安装sudoaptinstall ros-iron-fastdds fastddsgen 
5.2 定义数据结构(IDL)

创建 SensorData.idl

struct SensorData { unsigned long sensor_id; float temperature; float humidity; }; 
5.3 生成 C++ 代码
fastddsgen -replace SensorData.idl # 生成 Publisher/Subscriber 模板
5.4 编写发布者(Publisher)
#include"SensorDataPublisher.h"intmain(){// 创建参与者 DomainParticipant* participant =DomainParticipantFactory::get_instance()->create_participant(0);// 注册数据类型 SensorDataType data_type; participant->register_type(&data_type);// 创建发布者 Publisher* publisher = participant->create_publisher(PUBLISHER_QOS_DEFAULT); Topic* topic = participant->create_topic("SensorTopic", data_type.get_type_name()); DataWriter* writer = publisher->create_datawriter(topic); SensorData data; data.sensor_id(101); data.temperature(25.6); data.humidity(60.2);while(true){ writer->write(&data);// 发布数据 std::this_thread::sleep_for(std::chrono::seconds(1));}return0;}
5.5 编写订阅者(Subscriber)
#include"SensorDataSubscriber.h"classSensorListener:publicDataReaderListener{public:voidon_data_available(DataReader* reader)override{ SampleInfo info; SensorData data;if(reader->take_next_sample(&data,&info)== ReturnCode_t::RETCODE_OK){ std::cout <<"Received: SensorID="<< data.sensor_id()<<" Temp="<< data.temperature()<<" Humidity="<< data.humidity()<< std::endl;}}};intmain(){ DomainParticipant* participant =...// 同发布者 Subscriber* subscriber = participant->create_subscriber(SUBSCRIBER_QOS_DEFAULT); Topic* topic = participant->create_topic("SensorTopic","SensorData"); DataReader* reader = subscriber->create_datareader(topic); SensorListener listener; reader->set_listener(&listener);// 设置回调while(true);// 保持运行}
5.6 编译运行(CMake集成)
cmake_minimum_required(VERSION 3.10) project(FastDDS_Demo) find_package(fastdds REQUIRED) find_package(fastrtps REQUIRED) add_executable(publisher SensorDataPublisher.cpp) add_executable(subscriber SensorDataSubscriber.cpp) target_link_libraries(publisher eprosima::fastdds eprosima::fastrtps) target_link_libraries(subscriber eprosima::fastdds eprosima::fastrtps) 
mkdir build &&cd build cmake ..&&make ./publisher & ./subscriber # 启动两个终端

5.7通信流程总结
  1. 发布者和订阅者都创建它们的 DDS 实体
  2. Fast DDS 自动发现并匹配端点
  3. 发布者发送消息,这些消息被传递给订阅者

订阅者通过回调处理消息

在这里插入图片描述

涉及的关键概念

  1. DomainParticipant:DDS 的主要入口点。所有其他实体都由它创建。
  2. Topic:数据交换的命名通道。发布者和订阅者必须使用相同的主题名称才能通信。
  3. Data Type:您的数据结构,在 IDL 中定义并向参与者注册。
  4. Publisher/DataWriter:向主题发送数据。
  5. Subscriber/DataReader:从主题接收数据。
  6. Discovery:Fast DDS 自动发现网络中匹配的端点。

6. 进阶建议

安全加密(工业场景):

fastddsgen -security SensorData.idl # 启用 TLS 加密

QoS 动态调整

DataWriterQos qos; qos.reliability().kind = RELIABLE_RELIABILITY_QOS; qos.durability().kind = TRANSIENT_LOCAL_DURABILITY_QOS; publisher->create_datawriter(topic, qos);

启用共享内存传输(同机进程):

<!-- XML 配置 --><transport_descriptors><shared_memoryname="shm"segment_size="16MB"/></transport_descriptors>

性能实测数据(基准测试):共享内存传输:延迟 < 5μs千兆局域网 UDP:延迟 50~100μs数据传输速率:10Gbps+(零拷贝优化下)

Fast DDS 不仅是一个通信库,更是一套成熟的分布式数据总线方案,为 C++ 实时系统提供坚实的底层支撑。通过本文的代码案例,你可快速构建高可靠、低延迟的分布式应用。

7.扩展阅读 (Fast DDS 内部工作原理)

Fast DDS 的高效性源于 RTPS 协议的深度实现现代硬件优化(多核 CPU/共享内存)。

其核心工作原理可拆解为几大维度:

7.1 以数据为中心的对象模型 (DCPS)

Fast DDS 维护全局数据空间而非简单消息传递:

  • Domain 隔离:通过 DomainId_t 实现逻辑隔离(同域才能通信)
  • 缓存机制
    • DataWriter::write() → 写入发送缓存
    • DataReader::take() → 从接收缓存提取
  • 三重解耦
    • 时间解耦:发布/订阅无需同时在线
    • 空间解耦:无需知道对方位置
    • 类型解耦:IDL 静态类型保证一致性
7.2 自动发现机制 (Discovery Protocol)

去中心化 P2P 的核心

无需 Broker 的核心机制:

PDP (参与者发现):节点启动时,通过 UDP 多播(默认端口 7400)发送 DATA(p) 包。 广播内容:<应用ID, IP, 支持QoS>。结果:全网节点构建参与者列表

EDP (端点发现):参与者通过单播交换详细信息:发布者声明:"我Topic:/sensor/temp", 订阅者声明:"我需要 Topic:/sensor/temp"。匹配成功时,自动建立直达数据通道

  1. PDP (参与者发现):多播组参与者B多播组(239.255.0.1参与者A多播组参与者B多播组(239.255.0.1参与者A7400): DATA(p) [ID=A, IP=192.168.1.10]DATA(p) [ID=B, IP=192.168.1.20]ACK (单播)ACK (单播)
    • 通过 UDP 多播交换 DomainParticipant 信息
    • 建立全局参与者列表

EDP (端点发现)

// 端点匹配逻辑if(Publisher.Topic == Subscriber.Topic && Publisher.QoS.is_compatible(Subscriber.QoS)){establish_direct_connection();// 建立直达连接}
7.3 多层传输引擎

智能选择最优传输路径:

传输方式延迟使用场景激活条件
共享内存<5μs同机多进程检测到 localhost 连接
UDPv4/v650-100μs默认跨机传输自动首选
TCPv4/v61-10ms防火墙穿透/高丢包网络手动配置或 UDP 失败时
// 共享内存零拷贝实现voidshm_transport(){void* shared_mem =mmap(..., MAP_SHARED);// 内存映射memcpy(shared_mem, data, size);// 单次拷贝// 接收方直接访问内存映射区(零拷贝)}
7.4 数据序列化机制 (CDR)

二进制级高效编码

structSensorData{long id;// CDR 编码: 0x00000001 [4字节]float temp;// 0x42280000 [4字节]};// 内存布局 = [0x01,0x00,0x00,0x00, 0x00,0x00,0x28,0x42]
  • CDR 特性
  • 二进制对齐(兼容 C++ 内存布局)
  • 大端序/小端序自动转换
  • fastddsgen 生成类型特化序列化函数,速度比 JSON 快 100 倍

Fast DDS 本质是基于 RTPS 协议的状态机

  1. 发现层:UDP 多播建立参与者地图
  2. 传输层:共享内存/UDP 实现最短路径
  3. 数据层:CDR 编码榨干硬件性能
  4. 控制层:QoS 策略驱动状态流转

参考链接

https://blog.ZEEKLOG.net/xllhd100s/article/details/113472321
https://zread.ai/eProsima/Fast-DDS

Read more

用AList挂载网盘,无损看VR电影教程,无需下载到PICO头显本地!

用AList挂载网盘,无损看VR电影教程,无需下载到PICO头显本地!

用AList挂载网盘,无损看VR电影,不必下载到PICO头显本地! 标签:VR播放器|WebDAV|AList|115网盘|4XVR|资源挂载技巧 最近用PICO头显看片,经常遇到个烦事:要么是网盘资源太大,动不动几十GB,要么就是下完才发现是渣画质,还得删重下。某天一个同行安利我用 AList 挂载网盘,直接用4XVR播放器通过WebDAV在线看资源。试了几次,效果超棒!关键是不用占头显内存、不用传输时间,也几乎不会卡顿,看片体验直接起飞。 这篇文章我就把完整流程整理下来,保姆级图文教程,不管是安卓手机、PC,还是PICO头显用户都能无痛上手! 🔧 你需要准备: * 手机或电脑安装 AList 服务端 * 一个支持 WebDAV 的播放器(如 4XVR) * 一个支持挂载的网盘(推荐:115、阿里云盘) * 网盘账号 + Cookie 📥 安装 AList:安卓 / PC

By Ne0inhk
Windows 安装 Neo4j(2025最新·极简)

Windows 安装 Neo4j(2025最新·极简)

目录 1. 准备 2. 下载安装包 3. 一键安装 4. 启动 Neo4j 5.安装 Neo4j 的系统服务 Neo4j 是目前最流行的原生图数据库,用图结构(节点-关系-属性)存储数据,而非传统表结构。它专为海量关联数据设计,提供: * 原生图存储:基于免索引邻接结构,每个节点直接维护指向相邻节点的物理指针,实现 O(1) 时间复杂度的图遍历。 * Cypher 查询语言:ISO 标准化图查询语言,采用 ASCII-Art 模式匹配语法,支持可变长度路径、子图查询、聚合与更新混合事务。 * ACID 事务:支持完整事务、集群高可用,可承载企业级负载。 * 丰富生态:内置 Graph Data Science (GDS)

By Ne0inhk

养龙虾-------【多openclaw 对接飞书多应用】---多个大龙虾机器人群聊

🚀 MiniMax Token Plan 惊喜上线!新增语音、音乐、视频和图片生成权益。邀请好友享双重好礼,助力开发体验! 好友立享 9折 专属优惠 + Builder 权益,你赢返利 + 社区特权! 👉 立即参与:https://platform.minimaxi.com/subscribe/token-plan?code=2NMAwoNLlZ&source=link 最近玩了下大龙虾,对接飞书后玩的不亦乐乎,妥妥滴私人助理。但是也萌发一个想法,多个机器人可以自己聊天吗?那会不会把世界给聊翻了。于是我马上搜寻各个配置方式,却是找到了可以配置多个机器人得群聊方式。 1.首先创建多个应用添加机器人,分别和部署得多个openclaw系统对接具体对接参考我写的【 养龙虾-------【openclaw 对接飞书、钉钉、微信 】—移动AI助理】 2.手工拉群并添加机器人: 3.把群id配置进各个龙虾配置文件里面 接下来就可以群聊了

By Ne0inhk
喂饭级教程:OpenClaw 对接 QQ 机器人,本地/腾讯云都能用

喂饭级教程:OpenClaw 对接 QQ 机器人,本地/腾讯云都能用

文章目录 * 前言 * 一、选对路子:官方 Bot 还是个人号? * 方案 A:QQ 开放平台官方机器人 * 方案 B:个人 QQ 号变身机器人 * 二、环境准备:5 分钟搞定基础设施 * 1. 服务器/电脑要求 * 2. 安装 OpenClaw * 3. 配置大模型 API * 三、方案 A:对接 QQ 开放平台官方机器人 * Step 1:注册开发者并创建机器人 * Step 2:获取三件套凭证 * Step 3:配置 IP 白名单和沙箱 * Step 4:OpenClaw 端配置

By Ne0inhk