写在开篇·蓉儿又开新坑

上回说到,郭靖搞清楚了DDS通信行为的三个核心疑问——启动顺序不影响连接、发现广播是轻量的、同一Writer有顺序保证。

郭靖合上笔记本,若有所思:“蓉儿,你说了这么多‘自动发现’‘自动配对’,但我还是没亲眼看到——DDS到底是怎么从‘素不相识’到‘暗号配对’的?中间走了几步?发了哪些报文?”

黄蓉咬了口糖葫芦:“问得好!光说不练假把式。 今天就用一张完整的时序图,把DDS发现阶段的每一步数据流讲清楚——从ECU上电,到开始传业务数据,中间到底发生了什么。”

一、先回顾:DDS发现阶段要解决什么问题

黄蓉在白板上写下三个问题:

问题答案(DDS要做的事)
谁在?发现网络里有哪些DDS应用(DomainParticipant)
发什么?发现每个应用提供了哪些Writer(发布者),需要哪些Reader(订阅者)
谁和谁配?把Topic名字相同的Writer和Reader匹配起来

DDS发现分两步:先找人,再找内容。

二、完整交互数据流(时序图)

黄蓉画了一张完整的时序图,以摄像头ECU(发布者) 和域控制器ECU(订阅者) 为例:

┌─────────────────────────────────────────────────────────────────────────────┐
│              DDS发现阶段完整数据流(摄像头 → 域控)                            │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  摄像头ECU(发布者)                      域控制器ECU(订阅者)                │
│       │                                          │                          │
│       │ ========== 第一步:找人(SPDP) ==========│                          │
│       │                                          │                          │
│       │  ① SPDP广播                              │                          │
│       │  “我是摄像头,我的DomainParticipant       │                          │
│       │    GUID=xxx,我在这里!”                  │                          │
│       │─────────────────────────────────────────>│                          │
│       │                                          │                          │
│       │                                          │  ② SPDP广播              │
│       │                                          │  “我是域控,我的          │
│       │                                          │    DomainParticipant     │
│       │                                          │    GUID=yyy”             │
│       │<─────────────────────────────────────────│                          │
│       │                                          │                          │
│       │ ========== 第二步:找内容(SEDP) =========│                          │
│       │                                          │                          │
│       │  ③ SEDP广播                              │                          │
│       │  “我有一个Writer,Topic=/camera/front,    │                          │
│       │   数据类型=Image, QoS=BEST_EFFORT”        │                           │
│       │─────────────────────────────────────────>│                          │
│       │                                          │                          │
│       │                                          │  ④ SEDP广播              │
│       │                                          │  “我有一个Reader,        │
│       │                                          │    Topic=/camera/front,  │
│       │                                          │    数据类型=Image,        │
│       │                                          │    QoS=BEST_EFFORT”      │
│       │<─────────────────────────────────────────│                          │
│       │                                          │                          │
│       │ ========== 第三步:本地匹配 ==========     │                          │
│       │                                          │                          │
│       │  ⑤ 各自判断:                             │                          │
│       │     Topic相同?✅                        │                          │
│       │     数据类型相同?✅                      │                          │
│       │     QoS兼容?✅                          │                          │
│       │     → 匹配成功!                          │                          │
│       │                                          │                          │
│       │ ========== 第四步:建立连接 ==========     │                         │
│       │                                          │                          │
│       │  ⑥ 单播握手(互相告诉对方自己的地址)       │                          │
│       │<─────────────────────────────────────────>│                         │
│       │                                          │                          │
│       │  ⑦ 业务数据开始传输(单播)                │                          │
│       │  DATA(/camera/front, 图像数据)          │                          │
│       │─────────────────────────────────────────>│                          │
│       │                                          │                          │
│       │  ⑧ 可靠性反馈(如果需要)                  │                          │
│       │  AckNack / Heartbeat                     │                          │
│       │<─────────────────────────────────────────>│                         │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

三、每一步拆解:这些报文在干什么

黄蓉把时序图中的每一步拆开细讲:

第一步:找人(SPDP)

步骤报文类型谁发内容作用
①SPDP广播摄像头“我是摄像头,我的GUID=xxx,我在这里”告诉全网“我上线了”
②SPDP广播域控“我是域控,我的GUID=yyy,我在这里”告诉全网“我上线了”

SPDP = Simple Participant Discovery Protocol,简单的参与者发现协议。
GUID = 全局唯一标识符,每个DDS应用(DomainParticipant)有唯一的ID。

第二步:找内容(SEDP)

步骤报文类型谁发内容作用
③SEDP广播摄像头“我有一个Writer,Topic=/camera/front,数据类型=Image,QoS=BEST_EFFORT”告诉全网“我要发这个Topic”
④SEDP广播域控“我有一个Reader,Topic=/camera/front,数据类型=Image,QoS=BEST_EFFORT”告诉全网“我要收这个Topic”

SEDP = Simple Endpoint Discovery Protocol,简单的端点发现协议。
Writer和Reader都是“端点”,SEDP负责发现它们。

第三步:匹配

检查项摄像头的值域控的值匹配?
Topic名字/camera/front/camera/front✅
数据类型ImageImage✅
QoSBEST_EFFORTBEST_EFFORT✅

匹配成功后,DDS底层记录“摄像头Writer ←→ 域控Reader”这对关系。

第四步:建立连接 + 数据传输

步骤报文类型方向作用
⑥单播握手互相交换网络地址,建立点对点连接
⑦DATA摄像头→域控业务数据(图像、刹车指令等)
⑧AckNack/Heartbeat互相可靠性确认(如果配置了RELIABLE)

四、广播 vs 单播:什么时候用哪个

郭靖问出了关键问题:“哪些步骤用广播,哪些用单播?”

黄蓉画了一张表:

阶段报文类型发送方式原因
第一步SPDP广播不知道谁在,喊一嗓子让所有人都知道
第二步SEDP广播不知道谁感兴趣,喊一嗓子让所有人知道
第三步匹配本地计算不涉及网络通信
第四步握手单播已经知道对方是谁,点对点通信
第四步DATA单播只发给匹配的订阅者,不打扰别人
第四步AckNack单播点对点确认

核心原则:不知道对方是谁时用广播,知道对方是谁后用单播。

五、一个具体的匹配例子

黄蓉用一个具体的数字例子,把整个流程串起来:

┌─────────────────────────────────────────────────────────────────────────────┐
│                    具体匹配例子                                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  摄像头ECU:                                                                 │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │  DomainParticipant GUID = 0x1111                                    │    │
│  │  Writer:                                                           │    │
│  │    Topic = "/camera/front"                                          │    │
│  │    Type = "Image"                                                   │    │
│  │    QoS = BEST_EFFORT                                                │    │
│  │    Writer GUID = 0x1111:0x0001                                      │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                             │
│  域控制器ECU:                                                               │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │  DomainParticipant GUID = 0x2222                                    │    │ 
│  │  Reader:                                                           │    │
│  │    Topic = "/camera/front"                                          │    │
│  │    Type = "Image"                                                   │    │
│  │    QoS = BEST_EFFORT                                                │    │
│  │    Reader GUID = 0x2222:0x0001                                      │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                             │
│  匹配结果:                                                                  │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │  Writer 0x1111:0x0001 ←→ Reader 0x2222:0x0001                       │    │
│  │  (摄像头图像数据 → 域控)                                            │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

六、如果匹配失败会发生什么

郭靖问:“如果Topic名字写错了,或者QoS不一致,会怎样?”

黄蓉画了几个失败场景:

场景摄像头域控结果
Topic名字不一致/camera/front/camera/rear❌ 匹配失败,不连接
数据类型不一致ImageCompressedImage❌ 匹配失败,不连接
QoS不一致BEST_EFFORTRELIABLE❌ 匹配失败,不连接
完全一致/camera/front + Image + BEST_EFFORT相同✅ 匹配成功,连接

匹配失败时,DDS不会建立连接。应用层收不到任何数据,也不会报错——安静地失败。

七、黄蓉的小本本

郭靖翻开她的笔记本,上面写着:

DDS发现阶段四步走:

第一步:SPDP(找人) —— 广播“我上线了”
第二步:SEDP(找内容) —— 广播“我要发什么”“我要收什么”
第三步:匹配 —— 本地判断Topic、数据类型、QoS是否一致
第四步:建立连接+传数据 —— 单播握手,单播传业务数据

广播 vs 单播:

  • 不知道对方是谁 → 广播(SPDP、SEDP)

  • 知道对方是谁 → 单播(握手、DATA、AckNack)

一句话:先广播找人找内容,再单播传数据。素不相识怎成对?暗号配对天仙配。

写在最后

郭靖合上笔记本:“我终于明白了DDS发现阶段的完整流程——先广播找人(SPDP),再广播找内容(SEDP),然后本地匹配,最后单播传数据。不知道对方是谁时用广播,知道后用单播。”

黄蓉咬了口糖葫芦:“全明白了?”

郭靖点头:“明白了。SPDP找谁在,SEDP找谁发谁收,匹配成功就单播开干。素不相识怎成对?暗号配对天仙配。”

黄蓉眨眨眼:“那QoS到底有哪些策略?什么场景该用哪个?”

郭靖摇头。

“下篇预告:QoS花样真不少,刹车插队视频跑——DDS的QoS策略详解。”

打完收工,886。

更多推荐