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区分。

端点名称EntityIdParticipant APublisher 端Participant BSubscriber 端
SPDP Writer00 01 00 c2✅ 存在✅ 存在
SPDP Reader00 01 00 c7✅ 存在✅ 存在
SEDPPub Writer00 00 03 c2✅ 存在✅ 存在
SEDPPub Reader00 00 03 c7✅ 存在✅ 存在
SEDPSub Writer00 00 04 c2✅ 存在✅ 存在
SEDPSub Reader00 00 04 c7✅ 存在✅ 存在
PartMsg Writer00 02 00 c2✅ 存在✅ 存在
PartMsg Reader00 02 00 c7✅ 存在✅ 存在
User DataWriter01 00 00 03✅ 存在—
User DataReader00 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 DataSPDP(简单参与者发现协议)中广播参与者信息
DATA(w)Writer DataSEDP(简单端点发现协议)中通告 DataWriter 端点
DATA(r)Reader DataSEDP 中通告 DataReader 端点
DATAUser 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 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐