1 发现阶段

1.1 基础概念

1.1.1 RTPS 的层级结构

  Domain(域)
   └── Participant(参与者)
        ├── DataWriter(写端点)
        ├── DataWriter
        ├── DataReader(读端点)
        └── DataReader

  三层,各司其职:

  Domain(域)
  - 逻辑隔离单元,用一个整数 domainId 标识(比如 0、1、2)
  - 相同 domainId 的 Participant 才能互相通信,不同域完全隔离
  - 它本身不是实体,只是一个分组规则

  Participant(参与者)
  - 一个应用进程里的 DDS 实体容器,是网络上可寻址的单位
  - 拥有全局唯一的 GuidPrefix(GUID 的前 12 字节)
  - 持有自己的单播/多播地址(Locator)
  - 管理它下面所有的 Endpoint

  Endpoint(端点)= DataWriter / DataReader
  - 真正收发用户数据的实体
  - 每个 Endpoint 有自己的 EntityId(GUID 的后 4 字节)
  - 完整 GUID = Participant 的 GuidPrefix + Endpoint 的 EntityId

        GUID = GuidPrefix + EntityId
  - Writer 和 Reader 通过 Topic + 类型 + QoS 进行匹配

  1.1.2 发现阶段:谁在哪一步做什么

 注意:内置端点EntityID完全相同(规范硬编码),靠GUID Prefix区分。

端点名称 EntityId Participant APublisher 端 Participant BSubscriber 端
SPDP Writer 00 01 00 c2 ✅ 存在 ✅ 存在
SPDP Reader 00 01 00 c7 ✅ 存在 ✅ 存在
SEDPPub Writer 00 00 03 c2 ✅ 存在 ✅ 存在
SEDPPub Reader 00 00 03 c7 ✅ 存在 ✅ 存在
SEDPSub Writer 00 00 04 c2 ✅ 存在 ✅ 存在
SEDPSub Reader 00 00 04 c7 ✅ 存在 ✅ 存在
PartMsg Writer 00 02 00 c2 ✅ 存在 ✅ 存在
PartMsg Reader 00 02 00 c7 ✅ 存在 ✅ 存在
User DataWriter 01 00 00 03 ✅ 存在
User DataReader 00 00 01 04 ✅ 存在

发现分两个阶段,严格有先后顺序:

  阶段一:SPDP — 发现 Participant

  Participant A                                         Participant B
       |                                                                  |
       |-- DATA(p) --> 多播地址 (周期性) --------->|
       |<------------- 多播地址 (周期性) -- DATA(p)-|
       |                                                                  |
       |  双方各自记录:对方的 GuidPrefix、       |
       |  单播地址、租约时长等                            |
       |                                                                  |

  - 谁发: Participant
  - 发什么: DATA(p),内容是 SPDPdiscoveredParticipantData
  - 发给谁: 预定义的多播地址(同一 Domain 内所有 Participant 都监听)
  - 怎么发: 周期性发送,间隔可配置
  - 目的: 让大家知道"网络上有哪些 Participant,它们的地址在哪"
  - 使用的内置端点: SPDPbuiltinParticipantWriter / SPDPbuiltinParticipantReader

  阶段二:SEDP — 发现 Endpoint

  Participant A                                           Participant B
       |--- DATA(w) --> 单播给 B: 我有 Writer1 -->|
       |--- DATA(r) --> 单播给 B: 我有 Reader1 -->|
       |                                                                  |
       |<-- DATA(w) --- 单播给 A: 我有 Writer2 ---|
       |<-- DATA(r) --- 单播给 A: 我有 Reader3 ---|
       |                                                                   |
       |  双方各自比对 Topic、类型、QoS            |
       |  → Writer1 和 Reader3 匹配成功!          |
       |                                                                  |

  • 谁发: 还是 Participant,但代表的是它下面的各个 Endpoint
  • 发什么: DATA(w) 通告 Writer,DATA(r) 通告 Reader
  • 发给谁: SPDP 阶段已发现的 Participant 的单播地址(不再是多播)
  • 什么时候发: SPDP 发现新 Participant 后触发;之后每次本地新增/删除 Endpoint 也会发
  • 目的: 交换端点信息,让双方知道对面有哪些 Writer/Reader,进而做匹配
  • 使用的内置端点:
    • SEDPbuiltinPublicationsWriter/Reader — 交换 Writer 信息
    • SEDPbuiltinSubscriptionsWriter/Reader — 交换 Reader 信息

  三、总结对照

  层级           发现协议    发的消息      传输方式    做的事
  ─────────────────────────────────────────────────────────
  Domain         无                  无             无                只是隔离边界
  Participant    SPDP        DATA(p)       多播            "我在这里,地址是xxx"
  Endpoint       SEDP        DATA(w/r)    单播            "我有这些读写端点,Topic和QoS是xxx"
  ─────────────────────────────────────────────────────────
                                                      ↓
                                                匹配成功 → 建立通信

  • 为什么要分两阶段? 因为多播开销大。SPDP用多播只解决"谁在网上"这一个问题,剩下的端点细节全走单播,减少网络负担。
  • SPDP 是持续的: 即使发现完成,DATA(p) 也会周期性发送,用来维持租约(lease)。如果超过leaseDuration 没收到对方的 DATA(p),就认为对方掉线。
  • SEDP 是事件驱动的: 发现新 Participant 时触发一次全量交换,之后只在 Endpoint 增删时增量通告。
  • 在 RTPS 协议中,DATA(p) 是一种特殊的 DATA 子消息(Submessage),其中 (p) 代表 Participant。

1.1.3 DATA子消息

 1.1.3.1
子消息 含义 用途
DATA(p) Participant Data SPDP(简单参与者发现协议)中广播参与者信息
DATA(w) Writer Data SEDP(简单端点发现协议)中通告 DataWriter 端点
DATA(r) Reader Data SEDP 中通告 DataReader 端点
DATA User Data 传输用户层的实际业务数据
1.1.3.2 DATA(p)
  • 是 SPDPbuiltinParticipantWriter 发的,对端由 SPDPbuiltinParticipantReader 接收。
  • 每个 DDS Participant 启动后,会通过 SPDP 周期性地向预定义的多播地址发送 DATA(p) 消息
  • 内容是 SPDPdiscoveredParticipantData,包含:参与者的 GUID、协议版本、Vendor ID、默认单播/多播
  • Locator、租约时长(leaseDuration)等
  • 其他参与者收到后就能"发现"该参与者的存在,进而触发 SEDP 阶段的端点匹配

一、 步骤:

1. 每个 Participant 上线后,周期性组播 SPDP DATA(p)         

  • 初始阶段: 短间隔快发 (尽快被发现)                     
  • 之后: 长间隔慢发 (维护存在 + 供后来者发现)             
  • 切换依据: 时间,与匹配无关                             
  • 持续整个生命周期,直到退出                              

2. 收到新的远端 DATA(p) 后:                                 

  • 单播回发自己的 DATA(p) (快速完成双向发现)               
  • 从对端 DATA(p) 中提取: locator + builtinEndpointSet                                                        

3. 双方互知后,无条件进入 SEDP:                              

  • 交换各自的 DataWriter / DataReader 端点信息           
  • 通过 HEARTBEAT / ACKNACK / DATA 可靠传输                                                                    

4. SEDP 信息收齐后,本地执行匹配 (Matching):                 

  • Topic 名称相同?                                      
  • Type 名称兼容?                                      
  • QoS 策略兼容?(如 Reliability, Durability 等)          
  • 三者全部满足 → 建立 Writer↔Reader 关联                 
  • 任一不满足 → 不关联,但 SEDP 信息仍保留                                                                

5. 匹配成功后,用户数据传输开始

二、 简单理解整个发现流程:
  Participant A                          Participant B
      |--- DATA(p) 多播广播 --------->|   (SPDP: 我在这里!)
      |<-------- DATA(p) 多播广播 ----|   (SPDP: 我也在这里!)
      |--- DATA(w) / DATA(r) ------->|   (SEDP: 我有这些端点)
      |<-- DATA(w) / DATA(r) --------|   (SEDP: 我也有这些端点)
      |====== 匹配成功,开始通信 ======|   (DATA: 业务数据交换)

三、例子

组播

一上线快速发几包,然后进入周期发送

INFO_TS: Timestampt

子消息:时间戳0x09   DATA0x15

现在分析DATA的内容:

【RTPS消息头】

【子消息①】

【子消息②】

单播

【单播差距】

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐