Fast DDS实战:用Wireshark抓包拆解HelloWorld示例的完整通信流程(附pcap文件)
Fast DDS实战:用Wireshark抓包拆解HelloWorld示例的完整通信流程(附pcap文件)
当你第一次运行Fast DDS的HelloWorld示例时,看到终端输出"Publisher matched with Subscriber"的提示,是否好奇这两个进程究竟在背后交换了哪些信息?本文将带你像网络侦探一样,用Wireshark揭开DDS通信的神秘面纱。
1. 实验环境搭建与准备工作
在开始抓包前,我们需要一个干净的实验环境。建议使用两台物理机或虚拟机(IP分别为192.168.1.10和192.168.1.20),避免本地回环接口抓包的复杂性。安装以下组件:
- Fast DDS v2.10.0(当前最新稳定版)
- Wireshark 4.2.0(需安装RTPS协议解析插件)
- DDSHelloWorld示例程序(Fast DDS自带)
配置关键点:
# 在Publisher端执行 DDSHelloWorldExample publisher -s 100 -i 1000 # 在Subscriber端执行 DDSHelloWorldExample subscriber -s 100 -i 1000参数说明:
-s 100:发送100条消息-i 1000:每条消息间隔1000毫秒
提示:建议关闭防火墙和SELinux,避免干扰网络抓包。同时确保两台机器时钟同步(NTP服务),这对分析时间戳字段至关重要。
2. 抓包策略与RTPS协议基础
在Subscriber端启动Wireshark,选择正确的网卡后,应用以下过滤规则:
rtps && !rtps.participant_guid.prefix == 00:00:00:00:00:00:00:00:00:00:00:00RTPS报文结构速览:
| 字段类型 | 长度(bytes) | 说明 | 示例值 |
|---|---|---|---|
| Protocol ID | 4 | 固定为"RTPS" | 0x52545053 |
| Protocol Major | 1 | 主版本号(通常为2) | 0x02 |
| Protocol Minor | 1 | 次版本号(通常为3) | 0x03 |
| Vendor ID | 2 | 厂商标识(Fast DDS为0x010f) | 0x010f |
关键子消息类型及其作用:
- INFO_DST:标识目标参与者(类似IP包头中的目标地址)
- INFO_TS:携带时间戳信息(纳秒精度)
- DATA:实际传输的用户数据
- HEARTBEAT:Writer的状态通告
- ACKNACK:Reader的确认反馈
3. 发现阶段报文深度解析
启动程序后,首先观察到的是发现阶段的报文交换。这个阶段分为两个子阶段:
3.1 参与者发现(PDP)
典型抓包序列:
- 组播SPDP消息(目的地址239.255.0.1)
- 单播SPDP响应
- 重复步骤1-2(保活机制)
关键字段示例:
SPDPdiscoveredParticipantData: participantGuid.prefix = 0x000000000000000000000001 participantGuid.entityId = 0x0000c1 leaseDuration.seconds = 100 userData.value = "FastDDSv2.10"3.2 端点发现(SEDP)
这个阶段交换Writer和Reader的QoS信息。以Writer发现为例:
- Publisher发送DiscoveredWriterData:
writerProxy.remoteWriterGuid = 0x000000000000000000000001|0x000002c2 topicName = "HelloWorldTopic" typeName = "HelloWorld" reliability.kind = RELIABLE- Subscriber回复ACKNACK:
bitmapBase = 1 numBits = 0 finalFlag = true注意:发现阶段通常持续3-5秒,期间可能看到重复的HEARTBEAT和ACKNACK交换,这是正常的心跳机制。
4. 数据传输阶段实战分析
当终端显示"Publisher matched"后,真正的用户数据传输开始。我们以一条完整的"HelloWorld"消息为例:
发送序列:
- Publisher发送DATA报文:
RTPS DATA submessage: writerId = 0x000002c2 sequenceNumber = 1 serializedPayload = "Hello World! (1)"- Subscriber回复ACKNACK:
RTPS ACKNACK submessage: readerId = 0x000003c2 writerId = 0x000002c2 bitmapBase = 1 numBits = 0 (表示成功接收)关键时序分析:
| 时间戳(ms) | 事件类型 | 方向 | 关键参数 |
|---|---|---|---|
| 0 | DATA | Pub → Sub | seq=1, payload="(1)" |
| 0.8 | ACKNACK | Sub → Pub | ack seq=1 |
| 1000 | HEARTBEAT | Pub → Sub | first=1, last=1 |
| 1000.5 | ACKNACK | Sub → Pub | expect seq=2 |
5. 高级场景与异常分析
5.1 大消息分片处理
当消息超过MTU时,Fast DDS会进行分片传输。在Wireshark中可以看到:
- 原始DATA报文被标记为
DATA_FRAG - 分片信息字段:
fragmentStartingNum = 1 fragmentsInSubmessage = 3 fragmentSize = 1400
5.2 丢包重传场景
人为制造网络丢包(如用tc命令)后,观察到的恢复流程:
- Publisher发送HEARTBEAT(lastSeq=5)
- Subscriber发现缺失seq=3,回复:
ACKNACK: bitmapBase = 3 numBits = 1 bitmap = 0x1 (二进制01,表示缺失) - Publisher重传DATA(seq=3)
5.3 QoS策略对通信的影响
对比不同QoS设置下的报文差异:
| QoS类型 | 典型报文特征 | 适用场景 |
|---|---|---|
| BEST_EFFORT | 无ACKNACK,HEARTBEAT间隔长 | 低延迟,允许丢包 |
| RELIABLE | 密集的ACKNACK,HEARTBEAT间隔短 | 数据完整性要求高 |
| TRANSIENT | 发现阶段携带持久化数据 | 晚加入的订阅者 |
6. 实战技巧与性能优化
经过上百次抓包测试,总结出这些实用经验:
过滤技巧:
rtps && rtps.payload contains "Hello" // 只显示含Hello的消息 rtps.flags.final == 1 // 关键控制报文性能瓶颈识别:
- ACKNACK延迟>50ms → 检查网络延迟
- HEARTBEAT间隔异常 → 检查QoS配置
- DATA分片过多 → 考虑调整消息大小
Wireshark插件配置: 在
Preferences → Protocols → RTPS中:- 启用"Deserialize user data"
- 设置"Default encoding"为CDR_LE
附:本文分析的完整pcap文件已上传至示例仓库,包含以下场景:
- 正常通信流程
- 高延迟网络模拟
- 大消息分片传输
- 可靠性模式下的丢包恢复
