【 Fast-DDS 源码分析(一):架构总览与模块介绍】

Fast-DDS 源码分析(一):架构总览与模块介绍

系列规划:本文是 Fast-DDS 源码分析系列的开篇,对整体架构和各模块进行概要介绍。后续文章将逐一深入剖析各个核心模块。


目录

  • [一、Fast-DDS 简介](#一、Fast-DDS 简介)
    • [1.1 技术栈](#1.1 技术栈)
  • 二、顶层目录结构
  • [三、核心设计:双层 API 架构](#三、核心设计:双层 API 架构)
    • [3.1 为什么设计两层?](#3.1 为什么设计两层?)
    • [3.2 桥接模式(Bridge Pattern)](#3.2 桥接模式(Bridge Pattern))
  • [四、DDS 层核心实体](#四、DDS 层核心实体)
    • [4.1 实体层次结构](#4.1 实体层次结构)
    • [4.2 关键类职责](#4.2 关键类职责)
    • [4.3 典型使用流程](#4.3 典型使用流程)
  • [五、RTPS 层模块详解](#五、RTPS 层模块详解)
    • [5.1 模块全景图](#5.1 模块全景图)
    • [5.2 核心类继承层次](#5.2 核心类继承层次)
    • [5.3 发现协议(Discovery Protocol)](#5.3 发现协议(Discovery Protocol))
      • [PDP --- 参与者发现](#PDP — 参与者发现)
      • [EDP --- 端点发现](#EDP — 端点发现)
      • 发现流程
    • [5.4 消息发送与接收流程](#5.4 消息发送与接收流程)
      • [发送路径(Writer → 网络)](#发送路径(Writer → 网络))
      • [接收路径(网络 → Reader)](#接收路径(网络 → Reader))
    • [5.5 关键设计要点](#5.5 关键设计要点)
  • [六、传输层(Transport Layer)](#六、传输层(Transport Layer))
    • [6.1 传输类层次](#6.1 传输类层次)
    • [6.2 各传输方式特点](#6.2 各传输方式特点)
    • [6.3 SHM 传输原理](#6.3 SHM 传输原理)
    • [6.4 传输注册机制](#6.4 传输注册机制)
  • [七、安全模块(DDS Security)](#七、安全模块(DDS Security))
  • 八、其他重要模块
    • [8.1 流控制(FlowController)](#8.1 流控制(FlowController))
    • [8.2 历史缓存(History)](#8.2 历史缓存(History))
    • [8.3 持久化(Persistence)](#8.3 持久化(Persistence))
    • [8.4 统计与监控(Statistics)](#8.4 统计与监控(Statistics))
    • [8.5 X-Types 动态类型](#8.5 X-Types 动态类型)
    • [8.6 RPC(Request-Reply)](#8.6 RPC(Request-Reply))
  • 九、系列文章规划
  • 十、阅读源码的建议

一、Fast-DDS 简介

Fast-DDS (原名 Fast RTPS)是 eProsima 公司开源的 DDS(Data Distribution Service,数据分发服务)中间件实现,采用 Apache 2.0 许可证。它是:

  • OMG DDS 标准的 C++ 高性能实现
  • ROS 2(Robot Operating System 2)的默认通信中间件
  • 支持实时数据分发、发布-订阅模式、QoS 策略、安全加密等

技术栈

维度 详情
语言 C++(C++11 起)
构建 CMake(>= 3.22)
序列化 Fast-CDR(CDR 标准序列化)
内存 foonathan_memory(高效内存分配器)
网络 Asio + 原生 Socket(UDP/TCP/SHM)
XML TinyXML2
安全 OpenSSL(可选)

二、顶层目录结构

复制代码
Fast-DDS-master/
├── CMakeLists.txt           # 顶层 CMake 构建文件
├── include/fastdds/         # 公共头文件(对外 API)
│   ├── dds/                 # DDS 高层 API(发布-订阅模型)
│   └── rtps/                # RTPS 底层 API(写入者-读取者模型)
├── src/cpp/                 # 源码实现
│   ├── fastdds/             # DDS 层实现
│   ├── rtps/                # RTPS 协议层实现
│   ├── security/            # DDS Security 安全插件
│   ├── statistics/          # 统计与监控模块
│   ├── utils/               # 工具函数
│   └── xmlparser/           # XML 配置解析
├── examples/cpp/            # 13 个 C++ 示例
├── test/                    # 单元测试和集成测试
├── thirdparty/              # 第三方依赖
├── tools/                   # 辅助工具
├── fuzz/                    # 模糊测试
└── resources/               # XSD 模式等资源文件

三、核心设计:双层 API 架构

Fast-DDS 最核心的设计特点是 两层 API 架构,这是理解整个项目的关键。

复制代码
┌─────────────────────────────────────────────────────┐
│                    用户应用                           │
├─────────────────────────────────────────────────────┤
│  DDS 层(高层 API)                                   │
│  DomainParticipant / Publisher / Subscriber          │
│  DataWriter / DataReader / Topic                     │
│  ── 发布-订阅模型,符合 OMG DDS 标准                    │
├─────────────────────────────────────────────────────┤
│  RTPS 层(底层 API)                                   │
│  RTPSParticipant / RTPSWriter / RTPSReader           │
│  ── 写入者-读取者模型,直接操作 RTPS 协议                │
├─────────────────────────────────────────────────────┤
│  传输层                                               │
│  UDP / TCP / Shared Memory Transport                  │
└─────────────────────────────────────────────────────┘

为什么设计两层?

DDS 层 RTPS 层
抽象级别 面向应用的发布-订阅 面向协议的写入者-读取者
符合标准 OMG DDS 规范 OMG RTPS 规范
实体管理 DomainParticipant 统一管理 各自独立创建
适用场景 大多数应用开发 需要精细控制协议行为

桥接模式(Bridge Pattern)

DDS 层实体在内部持有 RTPS 层实体的指针,通过委托模式实现桥接:

DDS 实体 内部持有的 RTPS 实体
DomainParticipant RTPSParticipant*
Publisher 共享 DomainParticipantRTPSParticipant*
Subscriber 共享 DomainParticipantRTPSParticipant*
DataWriter BaseWriter*(RTPSWriter 的基类)
DataReader RTPSReader*
Topic 无直接 RTPS 对应(纯 DDS 概念)

四、DDS 层核心实体

实体层次结构

复制代码
Entity(抽象基类)
├── DomainEntity
│   └── DomainParticipant          ← 域的入口,管理所有实体
│       ├── 创建 Publisher
│       ├── 创建 Subscriber
│       └── 创建 Topic
├── Publisher                      ← 创建和管理 DataWriter
│   └── DataWriter                 ← 发布数据
├── Subscriber                     ← 创建和管理 DataReader
│   └── DataReader                 ← 订阅数据
├── Topic                          ← 数据主题
├── ContentFilteredTopic           ← 内容过滤主题
└── DomainParticipantFactory       ← 单例工厂,创建 DomainParticipant

关键类职责

头文件 职责
DomainParticipantFactory dds/domain/DomainParticipantFactory.hpp 单例工厂,管理所有 DomainParticipant
DomainParticipant dds/domain/DomainParticipant.hpp (64KB) 域参与者,应用的入口点
Publisher dds/publisher/Publisher.hpp (19KB) 发布者,管理 DataWriter 集合
Subscriber dds/subscriber/Subscriber.hpp (20KB) 订阅者,管理 DataReader 集合
DataWriter dds/publisher/DataWriter.hpp (27KB) 数据写入者,发布数据
DataReader dds/subscriber/DataReader.hpp (59KB) 数据读取者,订阅数据
Topic dds/topic/Topic.hpp 主题,定义数据的名称和类型
TypeSupport dds/topic/TypeSupport.hpp (16KB) 类型支持,处理序列化/反序列化

典型使用流程

cpp 复制代码
// 1. 创建 DomainParticipant
auto participant = DomainParticipantFactory::get_instance()
    ->create_participant(0, PARTICIPANT_QOS_DEFAULT);

// 2. 注册类型
TypeSupport type(new MyDataTypePubSubType());
type.register_type(participant, "MyDataType");

// 3. 创建 Topic
auto topic = participant->create_topic("MyTopic", "MyDataType", TOPIC_QOS_DEFAULT);

// 4. 创建 Publisher 和 DataWriter
auto publisher = participant->create_publisher(PUBLISHER_QOS_DEFAULT);
auto writer = publisher->create_datawriter(topic, DATAWRITER_QOS_DEFAULT);

// 5. 创建 Subscriber 和 DataReader
auto subscriber = participant->create_subscriber(SUBSCRIBER_QOS_DEFAULT);
auto reader = subscriber->create_datareader(topic, DATAREADER_QOS_DEFAULT);

// 6. 发布数据
MyDataType data;
writer->write(&data);

// 7. 订阅数据
MyDataType received_data;
SampleInfo info;
reader->take_next_sample(&received_data, &info);

五、RTPS 层模块详解

RTPS 层是 Fast-DDS 的核心,包含 17 个子模块

5.1 模块全景图

复制代码
src/cpp/rtps/
├── participant/        # RTPSParticipant 实现
├── writer/             # Writer 层次(Stateful/Stateless/Persistent)
├── reader/             # Reader 层次(Stateful/Stateless/Persistent)
├── builtin/            # 内置协议
│   └── discovery/      # 发现协议(PDP + EDP)
│       ├── participant/    # PDP:参与者发现
│       ├── endpoint/       # EDP:端点发现
│       └── database/       # 发现数据库(Discovery Server)
├── messages/           # RTPS 消息构造与解析
├── network/            # 网络工厂(NetworkFactory)
├── transport/          # 传输层(UDP/TCP/SHM)
├── flowcontrol/        # 流控制器
├── history/            # 历史缓存(CacheChange)
├── common/             # 通用类型(GUID/SequenceNumber/CacheChange/Time_t)
├── attributes/         # 属性定义
├── DataSharing/        # 数据共享(共享内存零拷贝)
├── domain/             # RTPSDomain 工厂
├── security/           # 安全插件接口
├── persistence/        # 持久化服务
├── resources/          # 资源管理(定时器/事件)
└── exceptions/         # RTPS 异常

5.2 核心类继承层次

Endpoint(端点)
复制代码
Endpoint
├── RTPSWriter(抽象接口)
│   └── BaseWriter
│       ├── StatefulWriter        ← 可靠通信(RELIABLE)
│       │   └── StatefulPersistentWriter
│       └── StatelessWriter       ← 尽力而为(BEST_EFFORT)
│           └── StatelessPersistentWriter
│
└── RTPSReader(抽象接口)
    └── BaseReader
        ├── StatefulReader        ← 可靠通信
        │   └── StatefulPersistentReader
        └── StatelessReader       ← 尽力而为
            └── StatelessPersistentReader

Stateful vs Stateless 的核心区别

Stateful Stateless
QoS RELIABLE BEST_EFFORT
Writer 侧 维护 ReaderProxy 列表,跟踪每个 Reader 的接收状态 仅维护 ReaderLocator 列表
Reader 侧 维护 WriterProxy 列表,跟踪序列号 不维护 Writer 状态
可靠性保证 ACKNACK 确认 + 重传机制 无保证
内存开销 较高 较低
Participant
复制代码
RTPSParticipant(公共 API 外观类)
└── RTPSParticipantImpl(实际实现)
    ├── 持有 BuiltinProtocols*
    ├── 持有 NetworkFactory
    ├── 持有 m_allWriterList / m_allReaderList
    ├── 持有 send_resource_list_ / m_receiverResourcelist
    └── 管理 FlowControllerFactory

5.3 发现协议(Discovery Protocol)

发现协议是 DDS 自动发现和匹配的核心,分为两层:

PDP(Participant Discovery Protocol)--- 参与者发现
复制代码
PDP(抽象基类)
├── PDPSimple          ← 标准 SimplePDP(多播 BEST_EFFORT)
├── PDPClient          ← Discovery Server 客户端
└── PDPServer          ← Discovery Server 服务端
  • 使用 SPDP(Simple PDP) 内置 Writer/Reader 交换 DATA(p) 子消息
  • PDPSimple 通过多播宣告自身存在
  • PDPClient/Server 通过单播 RELIABLE 通信,配合 DiscoveryDataBase 维护全局发现信息
EDP(Endpoint Discovery Protocol)--- 端点发现
复制代码
EDP(抽象基类)
├── EDPSimple          ← 标准 SimpleEDP(RELIABLE)
│   └── EDPServer      ← Discovery Server 端点发现
├── EDPStatic          ← 静态发现(XML 配置,无网络流量)
└── EDPClient          ← Discovery Server 客户端 EDP
  • 使用 SEDP(Simple EDP) 内置 Writer/Reader 交换 DATA(w)DATA(r) 子消息
  • validMatching() 方法检查 QoS 兼容性、Topic 匹配、Partition 匹配、TypeInfo 兼容性
  • EDPStatic 从 XML 文件读取端点信息,适用于静态配置场景
发现流程
复制代码
1. PDP::announceParticipantState()
   → SPDP Writer 发送 DATA(p)(多播或单播到 Discovery Server)
2. 远程 PDP 接收 DATA(p)
   → createParticipantProxyData()
   → assignRemoteEndpoints() → 匹配 SPDP/SEDP 内置端点
3. EDP::assignRemoteEndpoints()
   → 遍历远程参与者代理数据
   → pairingWriter() / pairingReader() → validMatching()
   → matched_writer_add() / matched_reader_add()
4. 本地 EDP 注册端点时
   → EDP::new_writer_proxy_data() / new_reader_proxy_data()
   → SEDP Writer 发送 DATA(w)/DATA(r)

5.4 消息发送与接收流程

发送路径(Writer → 网络)
复制代码
用户调用 DataWriter::write()
  │
  ▼
WriterHistory::add_change()                  # 创建 CacheChange_t,分配序列号
  │
  ▼
BaseWriter::unsent_change_added_to_history() # 通知 Writer 有未发送变更
  │
  ├─► [异步模式] FlowController::add_new_sample()
  │     └─► FlowControllerImpl 调度 → deliver_sample_nts()
  │
  └─► [同步模式] 直接调用 deliver_sample_nts()
        │
        ▼
  StatefulWriter::deliver_sample_nts()
    │
    ├─► 遍历 matched_readers_(ReaderProxy 列表)
    │     │
    │     ├─► 检查 Reader 是否需要此变更(reader_data_filter_)
    │     ├─► intraprocess_delivery() → 同进程直达 Reader
    │     │
    │     └─► [网络发送] RTPSMessageGroup::add_data()
    │           │
    │           ▼
    │         RTPSMessageCreator::addSubmessageData()   # 序列化 DATA 子消息
    │           │
    │           ▼
    │         RTPSMessageGroup(缓冲区管理,打包多个子消息)
    │           │
    │           ├─► addHeader() 添加 RTPS 头部
    │           ├─► 累积子消息直到缓冲区满或 flush()
    │           │
    │           ▼
    │         RTPSMessageGroup::flush() → LocatorSelectorSender::send()
    │           │
    │           ▼
    │         RTPSParticipantImpl::sendSync()
    │           │
    │           └─► 遍历 send_resource_list_ → SenderResource::send()
    │                 │
    │                 ▼
    │               TransportInterface(UDP/TCP/SHM)→ 网络
    │
    └─► [RELIABLE] 周期性 Heartbeat → ACKNACK 确认
接收路径(网络 → Reader)
复制代码
网络数据到达 → ReceiverResource 回调
  │
  ▼
MessageReceiver::processCDRMsg()
  │
  ├─► 解析 RTPS Header(GUID Prefix, Protocol Version, VendorId)
  ├─► 遍历所有 Submessage:
  │     ├─► DATA / DATA_FRAG    → 路由到目标 Reader → process_data_msg()
  │     ├─► HEARTBEAT           → 路由到目标 Reader → process_heartbeat_msg() → send_acknack()
  │     ├─► ACKNACK             → 路由到目标 Writer → process_acknack()
  │     ├─► GAP                 → 路由到目标 Reader → process_gap_msg()
  │     └─► INFO_TS / INFO_SRC / INFO_DST(元信息)
  │
  └─► DATA(p)/DATA(w)/DATA(r) → 路由到 BuiltinProtocols → PDP/EDP 处理

5.5 关键设计要点

  1. ReaderProxy / WriterProxy :StatefulWriter 为每个匹配的 Reader 维护 ReaderProxy(含 ACKNACK 状态、未发送变更列表);StatefulReader 为每个匹配的 Writer 维护 WriterProxy(含序列号跟踪)。

  2. FlowController:异步发布模式下,变更先加入 FlowController 队列,由专用线程调度发送,实现带宽限制和流量整形。

  3. RTPSMessageGroup:将多个子消息打包成一个 RTPS 报文,减少网络开销。

  4. Intraprocess 优化 :同一进程内的 Writer-Reader 对跳过序列化和网络发送,直接传递 CacheChange_t 指针。

  5. DataSharing :通过共享内存段实现零拷贝数据传输,由 DataSharingPoolDataSharingListener/Notifier 管理。


六、传输层(Transport Layer)

传输层负责实际的数据发送和接收,支持多种传输协议。

传输类层次

复制代码
TransportInterface(抽象基类)
├── UDPTransportInterface
│   ├── UDPv4Transport
│   └── UDPv6Transport
├── TCPTransportInterface
│   ├── TCPv4Transport
│   └── TCPv6Transport
├── SharedMemTransport       # 共享内存传输
├── ChainingTransport        # 链式适配器(可用于传输层叠加)
└── MulticastTransportInterface  # 多播传输接口

各传输方式特点

传输方式 适用场景 特点
UDP 同机 / 局域网 低延迟、支持多播、无连接
TCP 跨网络 / 广域网 可靠传输、面向连接、支持 TLS 加密
Shared Memory (SHM) 同机进程间 零拷贝、极低延迟、高吞吐

SHM 传输原理

SHM 传输基于 MultiProducerConsumerRingBuffer(多生产者-消费者环形缓冲区),通过以下组件协作:

  • SharedMemManager --- 管理共享内存段和端口
  • SharedMemGlobal --- 全局资源(端口 + 环形缓冲)
  • SharedMemTransport --- 传输实现
  • SHMLocator --- 共享内存定位器

传输注册机制

复制代码
NetworkFactory
├── 注册 TransportDescriptor → 创建 TransportInterface 实例
├── 构建 SenderResource 列表(发送通道)
├── 构建 ReceiverResource 列表(接收通道)
└── 根据 Locator 自动选择合适的传输

七、安全模块(DDS Security)

安全模块遵循 DDS Security 规范 1.1,采用三层插件架构:

复制代码
┌─────────────────────────────┐
│   Authentication(认证)     │  ← PKI + DH 密钥交换
├─────────────────────────────┤
│   AccessControl(访问控制)  │  ← Governance + Permissions XML
├─────────────────────────────┤
│   Cryptography(加密)       │  ← AES-GCM-GMAC
│   ├── CryptoTransform       │     消息加解密
│   ├── CryptoKeyExchange     │     密钥交换
│   └── CryptoKeyFactory      │     密钥工厂
└─────────────────────────────┘
实现类 功能
Authentication PKIDH (91KB) 验证本地/远程身份,Diffie-Hellman 密钥交换
AccessControl Permissions 解析权限文件,检查创建/读写权限
Cryptography AESGCMGMAC_* AES-GCM-GMAC 加解密 RTPS 子消息和 Payload

八、其他重要模块

8.1 流控制(FlowController)

复制代码
FlowController(抽象接口)
├── FlowControllerImpl           # 标准实现
├── FlowControllerFactory        # 工厂,管理多个 FlowController 实例
└── FlowControllerSchedulerPolicy # 调度策略
  • 异步模式下,数据变更先入队,由 FlowController 按策略调度发送
  • 支持带宽限制、优先级调度等

8.2 历史缓存(History)

复制代码
WriterHistory                  # 写入者历史
├── CacheChange_t 池管理
├── 序列号分配
└── 变更生命周期管理

ReaderHistory                  # 读取者历史
├── 接收的变更存储
└── 序列号排序和去重
  • CacheChange_t 是数据的核心载体,包含序列号、Payload、时间戳
  • CacheChangePool 提供预分配的对象池,避免动态内存分配

8.3 持久化(Persistence)

  • PersistenceService --- 持久化服务接口
  • SQLite3PersistenceService --- 基于 SQLite3 的实现
  • PersistentWriter/Reader --- 支持持久化的 Writer/Reader 变体
  • 用于保证重启后数据不丢失

8.4 统计与监控(Statistics)

  • MonitorService --- 监控服务核心
  • 提供 IConnectionsObserver, IProxyObserver, IStatusObserver 等接口
  • 可查询和监控实体状态、连接信息、QoS 指标

8.5 X-Types 动态类型

  • DynamicData (45KB) --- 运行时动态数据类型
  • DynamicType --- 动态类型定义
  • TypeObjectUtils (137KB) --- TypeObject 序列化/匹配工具
  • TypeLookupService --- 类型查询服务,实现类型自动传播

8.6 RPC(Request-Reply)

  • Requester / Replier --- 基于 DDS 的 RPC 模式
  • Service --- 服务定义
  • 通过 Request/Reply Topic 实现请求-回复语义

九、系列文章规划

基于以上模块分析,建议后续专题文章安排如下:

序号 主题 内容概要
(一) 架构总览与模块介绍 ← 本文
(二) DDS 层核心实体 DomainParticipant/Publisher/Subscriber/DataWriter/DataReader 的创建与生命周期
(三) RTPS Writer 深度剖析 StatefulWriter vs StatelessWriter,ReaderProxy,可靠传输机制
(四) RTPS Reader 深度剖析 StatefulReader vs StatelessReader,WriterProxy,ACKNACK 生成
(五) 发现协议(上):PDP SimplePDP/Discovery Server,参与者宣告与发现
(六) 发现协议(下):EDP SimpleEDP/StaticEDP,端点匹配与 QoS 兼容性检查
(七) 消息系统 RTPSMessageGroup/RTPSMessageCreator,子消息构造与解析
(八) 传输层详解 UDP/TCP/SHM 传输实现,通道管理
(九) QoS 策略实现 RELIABILITY/DUARABILITY/DEADLINE 等策略的内部实现
(十) 内存管理 CacheChangePool、foonathan_memory 集成、零拷贝
(十一) 安全模块 认证、访问控制、加密三层插件架构
(十二) 高级特性 X-Types/RPC/Statistics/FlowController/Persistence

十、阅读源码的建议

  1. 从示例入手examples/cpp/ 下有 13 个示例,从 HelloWorldExample 开始
  2. 跟踪 write() 调用链 :从 DataWriter::write() 一路追到网络发送,这是理解核心流程的最佳路径
  3. 关注 Impl 类 :公共 API 类大多是外观,真正的逻辑在 *Impl 类中
  4. 先理解 RTPS 层再回看 DDS 层:DDS 层本质上是对 RTPS 层的封装
  5. 善用 DDS 规范:OMG DDS 和 RTPS 规范是理解设计的权威参考

下一篇预告:DDS 层核心实体 --- DomainParticipant 的创建、QoS 转换与实体生命周期管理。

相关推荐
春天花会开1311 小时前
影像上传前置机网络架构设计模板(含VPN)
后端·架构
hypoy1 小时前
先拷问,再开工:grill-me + Trellis 重塑我的 Claude Code 工作流
架构·ai编程
TangentDomain1 小时前
AI 写代码时代,游戏 UI 架构为什么停在 MVP?
前端·游戏·架构
有什么事1 小时前
云手机多开哪个强?ARM架构:云手机多开的信任基石与性能核心
arm开发·智能手机·架构
YIN_尹1 小时前
探测+检测+缓解(PDM):让云租户自主防御微架构攻击
安全·缓存·架构
SL_staff2 小时前
《如何用规则引擎替代if-else?JVS-Rules可视化编排比硬编码强在哪里?》
java·低代码·架构
放下华子我只抽RuiKe52 小时前
FastAPI 全栈后端(六):中间件与依赖注入
ai·中间件·fastapi·ai编程·qwen·ai大模型·openclaw
一切皆是因缘际会3 小时前
从注意力归因到XAI落地
人工智能·深度学习·ai·架构
故渊at3 小时前
第九板块:Android 多媒体体系 | 第二十三篇:AudioFlinger 与 AudioPolicyService 音频架构
android·架构·音视频·audiopolicy·audioflinger