Fast DDS(原名 Fast RTPS)是 DDS 规范的一种高效且高性能的实现,DDS 是一种面向分布式应用软件的以数据为中心的通信中间件(DCPS)。本节将回顾 Fast DDS 的架构、操作和关键特性。
2.1 架构
Fast DDS 的架构如下图所示,其中展示了一个包含以下不同环境的分层模型。
- 应用层:利用 Fast DDS API 实现分布式系统通信的用户应用程序。
- Fast DDS 层:DDS 通信中间件的健壮实现。它允许部署一个或多个 DDS 域,在同一个域内的 DomainParticipant 通过在某个域主题下进行发布/订阅来交换消息。
- RTPS 层:实时发布订阅(RTPS)协议的实现,用于实现与 DDS 应用程序的互操作性。此层充当传输层的抽象层。
- 传输层:Fast DDS 可以运行于多种传输协议之上,例如不可靠传输协议(UDP)、可靠传输协议(TCP)或共享内存传输协议(SHM)。

Fast DDS 分层模型架构
2.1.1 DDS层
在 Fast DDS 的 DDS 层中定义了通信所需的几个关键元素。用户将在其应用程序中创建这些元素,从而引入 DDS 应用组件,构建一个以数据为中心的通信系统。遵循 DDS 规范,Fast DDS 将这些参与通信的元素定义为实体(Entity)。DDS 实体是任何支持服务质量配置(QoS)并实现了监听器的对象。
- QoS(服务质量):定义每个实体行为的机制。
- 监听器:在应用程序执行期间,实体通过此机制被通知可能发生的事件。
以下列出了 DDS 实体及其描述和功能。关于每个实体、其 QoS 及其监听器的更详细说明,请参阅《DDS 层》部分。
- 域。一个标识 DDS 域的正整数。每个 DomainParticipant 都将分配一个 DDS 域,以便相同域内的 DomainParticipant 可以通信,同时隔离不同 DDS 域之间的通信。应用程序开发者在创建 DomainParticipant 时必须指定此值。
- DomainParticipant。包含其他 DDS 实体(如发布者、订阅者、主题和多主题)的对象。它是允许创建其所包含的上述实体并配置其行为的实体。
- 发布者。发布者使用 DataWriter 在某个主题下发布数据,DataWriter 将数据写入传输层。它是创建和配置其所包含的 DataWriter 实体的实体,并且可以包含一个或多个 DataWriter。
- DataWriter。负责发布消息的实体。用户在创建此实体时必须提供一个 Topic,这将是数据发布所依据的主题。发布是通过将数据对象作为变更写入 DataWriter 的历史记录(History)中完成的。
- DataWriterHistory。这是一个数据对象变更的列表。当 DataWriter 开始在特定 Topic 下发布数据时,它实际上创建了该数据的一个变更。正是这个变更被记录在历史记录中。然后,这些变更被发送给订阅该特定主题的 DataReader。
- 订阅者。订阅者使用 DataReader 订阅某个主题,DataReader 从传输层读取数据。它是创建和配置其所包含的 DataReader 实体的实体,并且可以包含一个或多个 DataReader 实体。
- DataReader。订阅主题以接收发布内容的实体。用户在创建此实体时必须提供一个订阅主题。DataReader 将接收到的消息作为其 DataReader 历史记录(DataReaderHistory)中的变更来接收。
- DataReaderHistory。它包含了 DataReader 因订阅特定主题而接收到的数据对象的变更。
- Topic。将发布者的 DataWriter 与订阅者的 DataReader 绑定起来的实体。
2.1.2 RTPS层
如上所述,Fast DDS 中的 RTPS 协议允许将 DDS 应用实体从传输层中抽象出来。根据上图所示,RTPS 层有四个主要的实体。
- RTPSDomain:DDS 域在 RTPS 协议中的延伸。
- RTPSParticipant:包含其他 RTPS 实体的实体。它允许配置和创建其所包含的实体。
- RTPSWriter:消息的来源。它读取写入 DataWriterHistory 的变更,并将它们传输给所有先前已匹配的 RTPSReader。
- RTPSReader:消息的接收实体。它将 RTPSWriter 报告的变更写入 DataReaderHistory。
有关每个实体、其属性及其监听器的更详细说明,请参阅《RTPS 层》部分。
2.1.3 传输层
Fast DDS 支持在多种传输协议之上实现应用程序。这些协议包括 UDPv4、UDPv6、TCPv4、TCPv6 和共享内存传输(SHM)。默认情况下,DomainParticipant 会启用 UDPv4 和 SHM 传输协议。所有支持的传输协议的配置详情,请参阅《传输层》部分。
2.2 编程与执行模型
Fast DDS 是并发的且基于事件驱动的。以下将解释支配 Fast DDS 运行的多线程模型以及可能的事件。
2.2.1 并发与多线程
Fast DDS 实现了一个并发的多线程系统。每个 DomainParticipant 会生成一组线程来处理后台任务,例如日志记录、消息接收和异步通信。这不应该影响您使用库的方式,即 Fast DDS API 是线程安全的,因此您可以从不同线程中放心地对同一个 DomainParticipant 调用任何方法。但是,当外部函数访问由库内部运行的线程修改的资源时,必须考虑这种多线程实现。一个例子是实体监听器回调中被修改的资源。
Fast DDS 生成的全部线程如下所示。与传输相关的线程(标记为 UDP、TCP 和 SHM 类型)仅在使用相应的传输协议时才会被创建。
名字:Event
类型:General
基数:每个 DomainParticipant 一个线程
OS线程名:dds.ev.<participant_id>
描述:处理周期性和触发性的时间事件。请参阅 DomainParticipantQos。
名字:Discovery Server Event类型:General
基数:每个 DomainParticipant 一个线程
OS线程名:dds.ds_ev.<participant_id>
描述:同步对发现服务器数据库的访问。请参阅 DomainParticipantQos。
名字:Asynchronous Writer类型:General
基数:每个启用的异步流控制器一个线程。最少 1 个。
OS线程名:
dds.asyn.<participant_id>.<async_flow_controller_index>描述:管理异步写入操作。即使是同步写入器,某些形式的通信也必须在后台启动。请参阅 DomainParticipantQos和 FlowControllersQos。
名字:Datasharing Listener类型:General
基数:每个 DomainParticipant 一个线程
OS线程名:dds.dsha.<reader_id>
描述:处理通过数据共享(Datasharing)接收到的消息的监听器线程。请参阅 DataReaderQos。
名字:Reception类型:UDP
基数:每个端口一个线程
OS线程名:dds.udp.<port>
描述:处理传入的 UDP 消息的监听器线程。请参阅 `TransportConfigQos` 和 `UDPTransportDescriptor`。
名字:Reception类型:TCP
基数:每个 TCP 连接一个线程
OS线程名:dds.tcp.<port>
描述:处理传入的 TCP 消息的监听器线程。请参阅 `TCPTransportDescriptor`。
名字:Accept类型:TCP
基数:每个 TCP 连接一个线程
OS线程名:dds.tcp_accept
描述:处理传入的 TCP 连接请求的线程。请参阅 `TCPTransportDescriptor`。
名字:Keep Alive类型:TCP
基数:每个 TCP 连接一个线程
OS线程名:dds.tcp_keep
描述:用于维护 TCP 连接存活(keep-alive)的线程。请参阅 `TCPTransportDescriptor`。
名字:Reception类型:SHM
基数:每个端口一个线程
OS线程名:dds.shm.<port>
描述:通过 SHM 段处理传入消息的监听器线程。请参阅 `TransportConfigQos` 和 `SharedMemTransportDescriptor`。
名字:Logging类型:SHM
基数:每个端口一个线程
OS线程名:dds.shmd.<port>
描述:将传输的数据包存储并转储到文件中。请参阅 `TransportConfigQos` 和 `SharedMemTransportDescriptor`。
名字:Watchdog类型:SHM
基数:一个线程
OS线程名:dds.shm.wdog
描述:监控打开的共享内存段的健康状况。请参阅 `TransportConfigQos` 和 `SharedMemTransportDescriptor`。
名字:General Logging类型:Log
基数:一个线程
OS线程名:dds.log
描述:累积日志条目并将其写入相应的日志消费者。请参阅《日志记录线程》。
名字:Security Logging类型:Log
基数:每个 DomainParticipant 一个线程
OS线程名:dds.slog.<participant_id>
描述:累积并写入安全日志条目。请参阅 `DomainParticipantQos`。
名字:Watchdog类型:Filewatch
基数:一个线程
OS线程名:dds.fwatch
描述:监控被监视文件的状态以检测修改。请参阅 `DomainParticipantFactoryQos`。
名字:Callback类型:Filewatch
基数:一个线程
OS线程名:dds.fwatch.cb
描述:当被监视的文件发生变化时,运行已注册的回调函数。请参阅 `DomainParticipantFactoryQos`。
名字:Reception类型:TypeLookup Service
基数:每个 DomainParticipant 两个线程
OS线程名:
dds.tls.replies.<participant_id>dds.tls.requests.<participant_id>描述:当接收到带有未知数据类型的远程端点发现信息时运行。
其中一些线程仅在满足特定条件时才会生成:
- 数据共享监听器线程:仅当启用了数据共享(Datasharing)时才会创建。
- 发现服务器事件线程:仅当 DomainParticipant 被配置为发现服务器(Discovery Server)的 SERVER 时才会创建。
- TCP keep-alive 线程:需要将 keep-alive 周期配置为大于零的值。
- 安全日志记录和共享内存数据包日志记录线程:都需要启用特定的配置选项。
- 文件监控线程:仅当使用了 FASTDDS_ENVIRONMENT_FILE 时才会生成。
关于传输线程,Fast DDS 默认同时使用 UDP 和共享内存传输。端口配置可以根据部署的具体需求进行调整,但默认配置始终使用一个元流量端口和一个单播用户流量端口。这一规则同时适用于 UDP 和共享内存(因为 TCP 不支持多播)。更多信息可在《默认监听定位器》页面找到。
Fast DDS 提供了通过 ThreadSettings 配置其所创建线程的某些属性的可能性。
2.2.2 事件驱动架构
存在一个时间事件系统,使 Fast DDS 能够响应特定条件并安排周期性操作。其中少数对用户可见,因为大多数与 DDS 和 RTPS 元数据相关。但是,用户可以通过继承 TimedEvent 类在其应用程序中定义周期性的时间事件。
2.3 功能特性
Fast DDS 提供了一些附加功能,用户可以在其应用程序中实现和配置这些功能。概述如下。
2.3.1 发现协议
发现协议定义了在特定主题下发布的 DataWriter 与订阅同一主题的 DataReader 如何相互匹配,从而开始共享数据的机制。这适用于通信过程中的任何时刻。Fast DDS 提供以下发现机制:
- 简单发现。这是默认的发现机制,在 RTPS 标准中有定义,并提供了与其他 DDS 实现的兼容性。在此机制下,DomainParticipant 在早期阶段被单独发现,随后再匹配它们所实现的 DataWriter 和 DataReader。
- 发现服务器。这种发现机制使用集中式发现架构,其中服务器充当元流量发现的中枢。
- 静态发现。这种机制实现了 DomainParticipant 之间的相互发现,但如果远程 DomainParticipant 预先知道每个 DomainParticipant 所包含的实体(DataReader/DataWriter),则可以跳过这些实体的发现步骤。
- 手动发现。此机制仅与 RTPS 层兼容。它允许用户使用其选择的任何外部元信息通道,手动匹配和取消匹配 RTPSParticipant、RTPSWriter 和 RTPSReader。
Fast DDS 中实现的所有发现协议的详细说明和配置,请参见《发现》部分。
2.3.2 安全机制
Fast DDS 可以通过在以下三个级别实现可插拔的安全机制,来配置安全的通信:
- 远程 DomainParticipant 的身份验证。DDS:Auth:PKI-DH 插件通过使用可信证书颁发机构(CA)和 ECDSA 数字签名算法来执行相互认证,从而提供身份验证。它还使用椭圆曲线 Diffie-Hellman(ECDH)或 MODP-2048 Diffie-Hellman(DH)作为密钥协商协议来建立共享密钥。
- 实体的访问控制。DDS:Access:Permissions 插件在 DDS 域和主题级别为 DomainParticipant 提供访问控制。
- 数据加密。DDS:Crypto:AES-GCM-GMAC 插件使用伽罗瓦计数器模式(AES-GCM)的高级加密标准(AES)提供经过身份验证的加密。
有关 Fast DDS 中安全配置的更多信息,请参阅《安全》部分。
2.3.3 日志系统
Fast DDS 提供了一个可扩展的日志系统。Log 类是日志系统的入口点。它暴露了三个宏定义以方便使用:EPROSIMA_LOG_INFO、EPROSIMA_LOG_WARNING 和 EPROSIMA_LOG_ERROR。此外,除了已有的类别(INFO_MSG、WARN_MSG 和 ERROR_MSG)外,它还允许定义新的日志类别。它提供了使用正则表达式按类别进行过滤的功能,以及对日志系统详细程度的控制。有关日志系统可能配置的详细信息,请参阅《日志系统》部分。
2.3.4 XML 配置文件配置
Fast DDS 提供了通过使用 XML 配置文件 来更改其默认设置的可能性。因此,可以在用户无需实现任何程序源代码或重新构建现有应用程序的情况下,修改 DDS 实体的行为。
用户拥有针对每个 API 功能的 XML 标签。因此,可以通过 <participant> 标签构建和配置 DomainParticipant 配置文件,或者分别使用 <data_writer> 和 <data_reader> 标签构建 DataWriter 和 DataReader 配置文件。
为了更好地理解如何编写和使用这些 XML 配置文件,您可以继续阅读《XML 配置文件》部分。
2.3.5 环境变量
环境变量是通过操作系统功能在程序作用域之外定义的变量。Fast DDS 依赖于环境变量,以便用户可以轻松定制 DDS 应用程序的默认设置。有关影响 Fast DDS 的环境变量的完整列表和说明,请参阅《环境变量》部分。