按照RTPS协议中描述的,动态发现协议包含PDP(参与者发现协议)和EDP(端点发现协议)两种协议。
不论是发布端还是订阅端程序,创建域参与者时,都会默认创建8个内置端点:
1. 参与者发现协议PDP,2个端点分别为SPDPWriter和SPDPReader,这两个端点的作用是被用来发送和接收参与者信息数据。
2. 端点发现协议EDP,4个端点分别为SEDPPubWriter、SEDPPubReader、SEDPSubWriter、SEDPSubReader。这个四个端点被用来发送和接收用户端点(UserWriter,UserReader)信息数据。
3. 写入者活跃性协议WLP(WriterLivelinessProtocol),2个端点分别为builtinRTPSParticipantMEssageWriter和builtinRTPSParticipantMEssageReader。
发布端和订阅端这个8个端点的消息交互如图2-1所示,双向实线箭头表示端点之间消息交互。
图2-1中UserWriter和UserReader不属于内置端点,暂时称为用户端点(该端点是真正被用户用来,发送和接收用户数据的端点)。可以看出图2-1 中端点之间消息交互都是一一对应的,即一个Writer端点对应一个Reader端点。
发布端和订阅端通过动态发现协议完成匹配的过程如图2-2所示
下面通过先在一台PC上运行HelloworldExample订阅端,再在另外一台PC上运行HelloworldExample发布端,截取通信的码流,来详细分析发布端和订阅端的完成匹配的交互流程。
如下图所示,图2-3:
No.70~No.74的码流,属于内置端点SPDPWriter和SPDPReader之间传递的消息。DATA(p)子消息携带的是参与者信息的数据。该子消息的作用就是通知其他参与者,本参与者已上线。对应图2-2中的步骤①。属于参与者发现阶段。
No.75~No.109的码流,属于EDP(SEDPPubWriter、SEDPPubReader、SEDPSubWriter、SEDPSubReader)、WLP(builtinRTPSParticipantMEssageWriter、builtinRTPSParticipantMEssageReader)内置端点之间传递的消息。其中,EDP内置端点产生的消息码流,完成的是传递用户端点信息数据,使得用户端点互相发现对方,完成匹配。对应图2-2中的步骤②,③,④。属于端点发现阶段。
下面是结合wireshark码流和代码的详细解析,先看PDP,下一章解析EDP。
PDP
图2-3 红色方框部分 DATA(p)子消息包含参与者信息的数据。可以发现该消息是通过组播发送的(目的ip地址都是239.255.0.1)。该数据不仅在发布端/订阅端匹配的时候会被发送,而且发布端/订阅端都会启动一个定时器,每隔40秒重发一次各自的参与者信息数据。
图2-3中红色方框标记的部分有5条PDP消息,其中发布端(192.168.1.7)发送3条,订阅端(192.168.1.169)发送2条。
图2-4 中PDP消息发送的时序对应图2-3 中的码流顺序。70,73,74是发布端发送的3次PDP消息,71,72是订阅端发送的2次PDP消息。实际上发布端和订阅端发送的PDP消息次数是一样的,各发送3次PDP消息,发送PDP消息的流程也是一样的。
由于笔者是在订阅端运行后,才运行的wireshark,所以订阅端发送的第一条PDP消息,没有被wireshark捕获。
另外,图2-4中的发布端和订阅端PDP消息交互时序,受网络环境和系统影响,每次测试,捕获的PDP消息交互时序可能不一样。但是发布端和订阅端的PDP消息流程是一致的。
下面以发布端为例,列出70,73,74消息发送的对应的源码具体位置。
70:该消息是在创建参与者时,初始化内置协议完成后发送。源码位置如下:
对应的调用堆栈:
73:该消息是在发布端收到订阅端的PDP消息的时候,立刻又发送了一次PDP消息。 源码如下:
对应的调用堆栈:
74:该消息是在发布端收到订阅端的PDP消息时,SPDPWriter完成匹配一个远端的SPDPReader,这时唤醒异步写线程,发送自己的历史数据(即PDP消息)。需要说明一点,PDP消息存放在SPDPWriter的历史缓存中,由SPDPWriter负责发送。
唤醒异步写线程,代码如下:
调用堆栈:
异步写线程类在线程中回调SPDPWriter的send_any_unsent_changes()函数发送PDP消息。异步线程代码如下:
订阅端发送PDP消息的流程和发布端一致。这里不再详述。