8.3.7 RTPS 子消息
RTPS 协议版本 2.4 定义了几种子消息。它们分为两组:实体子消息和解释器子消息。实体子消息针对一个 RTPS 实体。解释器子消息修改 RTPS 接收器状态并提供上下文,帮助处理后续的实体子消息。
实体子消息包括:
• Data(数据):包含关于应用程序 Data 对象值的信息。Data 子消息由写入者(Writers)发送给读取者(Readers)。
• DataFrag(数据片段):相当于 Data,但仅包含新值的一部分(一个或多个片段)。允许数据作为多个片段传输,以克服传输消息大小限制。
• Heartbeat(心跳):描述写入者中可用信息。Heartbeat 消息由写入者发送给一个或多个读取者。
• HeartbeatFrag(心跳片段):对于分段数据,描述写入者中哪些片段可用。HeartbeatFrag 消息由写入者发送给一个或多个读取者。
• Gap(间隙):描述对读取者不再相关的信息。Gap 消息由写入者发送给一个或多个读取者。
• AckNack(确认/否认):向写入者提供关于读取者状态的信息。AckNack 消息由读取者发送给一个或多个写入者。
• NackFrag(否认片段):向写入者提供关于读取者状态的信息,具体是读取者仍然缺少哪些片段。NackFrag 消息由读取者发送给一个或多个写入者。
解释器子消息包括:
• InfoSource(信息源):提供关于后续实体子消息来源的信息。此子消息主要用于中继 RTPS 子消息。这在当前规范中未讨论。
• InfoDestination(信息目标):提供关于后续实体子消息最终目标的信息。此子消息主要用于中继 RTPS 子消息。这在当前规范中未讨论。
• InfoReply(信息回复):提供关于在后续子消息中出现的实体回复的信息。
• InfoTimestamp(信息时间戳):为后续实体子消息提供源时间戳。
• Pad(填充):如果需要进行内存对齐,则用于向消息添加填充。
图8.13 RTPS 子消息
这个子条款描述了每个子消息及其解释。每个子消息都以表 8.33 中描述的标题方式进行描述。
表 8.33 – 用于描述每个子消息的方案
Heading | Meaning |
Purpose | Submessage 主要目的的高层描述 |
Content | SubmessageHeader 的描述(SubmessageId 和 flags)。描述可能出现在 Submessage 中的 SubmessageElements。 |
Validity Constraints | Submessage 必须满足的有效性约束条件,以使其有效。 |
Change in State of the Receiver | 在 Message 中,一个 Submessage 的解释和含义可能取决于同一 Message 中之前的 Submessages。如 8.3.4 中所述,此上下文被建模为 Receiver 对象的状态变化。 |
Logical Interpretation | Submessage 应该如何解释的描述。 |
8.3.7.1 AckNack
8.3.7.1.1 Purpose
该子消息用于向写入者通报读取者的状态。该子消息允许读取者告知写入者它已接收到的序列号以及仍然缺失的序列号。这个子消息可用于进行积极和消极的确认。
8.3.7.1.2 Content
构成 AckNack 消息结构的元素在下表中描述。
Table 8.34 - AckNack 子消息的结构
Element | Type | Meaning |
EndiannessFlag | SubmessageFlag | 出现在 Submessage 头标志中。指示字节序(Endianness)。 |
FinalFlag | SubmessageFlag | 出现在 Submessage 头标志中。指示对于写入者是否强制要求响应。 |
readerId | EntityId | 标识确认接收某些序列号和/或请求接收某些序列号的读取者实体。 |
writerId | EntityId | 标识是 AckNack 消息的目标的写入者实体。这是被要求重新发送某些序列号或被告知接收了某些序列号的写入者实体。 |
readerSNState | SequenceNumberSet | 向写入者通信读取者的状态。所有序列号直到 readerSNState.base 之前都被读取者确认已收到。集合中出现的序列号指示读取者端缺失的序列号。集合中未出现的序列号是不确定的(可能已接收,也可能未接收)。 |
count | Count | 每次发送新的 AckNack 消息时递增的计数器。为写入者提供检测由于冗余通信路径而导致的重复 AckNack 消息的手段。 |
8.3.7.1.3 有效性
当以下任何一项为真时,此子消息无效:
-
Submessage 头中的 submessageLength 太小。
-
readerSNState 无效(如第8.3.5.5节定义)。
8.3.7.1.4 接收者状态的变化
无
8.3.7.1.5 逻辑解释
读取者向写入者发送 AckNack 消息,以传达其关于写入者使用的序列号的状态。 写入者通过其全局唯一标识(GUID)唯一标识。写入者的 GUID 使用接收者的状态获取:
writerGUID = { Receiver.destGuidPrefix, AckNack.writerId }
读取者通过其全局唯一标识(GUID)唯一标识。读取者的 GUID 使用接收者的状态获取:
readerGUID = { Receiver.sourceGuidPrefix, AckNack.readerId }
该消息同时具有两个目的:
-
子消息确认所有序列号,包括 SequenceNumberSet 中最低序列号之前的那个(即 readerSNState.base -1)。
-
子消息负面确认(请求)显式出现在集合中的序列号。
显式表示序列号的机制取决于 PSM。通常,使用紧凑的表示(例如位图)。 FinalFlag 指示读取者是否期望写入者发送心跳,或者决定由写入者决定。此标志的使用在第8.4节中描述。
8.3.7.2 数据
此子消息从 RTPS 写入者发送到 RTPS 读取者。
8.3.7.2.1 目的
此子消息通知 RTPS 读取者数据对象发生了变化,该对象属于 RTPS 写入者。可能的更改包括对值的更改以及对数据对象生命周期的更改。
8.3.7.2.2 内容
构成 Data 消息结构的元素在下表中描述。 表 8.35 Data 子消息的结构
Element | Type | Meaning |
EndiannessFlag | SubmessageFlag | 出现在 Submessage 头标志中。指示字节序(Endianness)。 |
InlineQosFlag | SubmessageFlag | 出现在 Submessage 头标志中。向 Reader 指示包含应用于解释消息的 QoS 参数的 ParameterList 的存在。 |
DataFlag | SubmessageFlag | 出现在 Submessage 头标志中。向 Reader 指示 dataPayload 子消息元素包含数据对象的序列化值。 |
KeyFlag | SubmessageFlag | 出现在 Submessage 头标志中。向 Reader 指示 dataPayload 子消息元素包含数据对象键的序列化值。 |
NonStandardPayloadFlag | SubmessageFlag | 出现在 Submessage 头标志中。向 Reader 指示 serializedPayload 子消息元素的格式不符合第 10 节的规定。 |
readerId | EntityId | 标识被通知数据对象变化的 RTPS Reader 实体。 |
writerId | EntityId | 标识对数据对象进行更改的 RTPS Writer 实体。 |
writerSN | SequenceNumber | 为所有由 writerGuid 标识的 RTPS Writer 进行的更改唯一标识更改和相对顺序。每个更改都有一个连续的序列号。每个 RTPS Writer 都维护其自己的序列号。 |
inlineQos | ParameterList | 仅在头中设置了 InlineQosFlag 时出现。包含可能影响消息解释的 QoS。 |
serializedPayload | SerializedPayload | 仅在头中设置了 DataFlag 或 KeyFlag 时出现。如果设置了 DataFlag,则包含更改后数据对象的新值。如果设置了 KeyFlag,则包含消息引用的数据对象的键。 |
8.3.7.2.2.3 有效性
当以下情况之一成立时,此子消息无效:
-
Submessage header的submessageLength过小。
-
writerSN.value不是严格正数(1, 2, ...),或为SEQUENCENUMBER_UNKNOWN。
-
inlineQos无效。
8.3.7.2.4 Receiver状态变化
无
8.3.7.2.5 逻辑解释
RTPS Writer向RTPS Reader发送Data子消息,以传达写入者内数据对象的变化。变化包括值的变化以及数据对象生命周期的变化。
值的变化通过serializedPayload的存在进行通信。当存在时,serializedPayload被解释为数据对象的值或唯一标识数据对象的键。
-
如果DataFlag被设置而KeyFlag没有被设置,serializedPayload元素被解释为数据对象的值。
-
如果KeyFlag被设置而DataFlag没有被设置,serializedPayload元素被解释为标识数据对象注册实例的键的值。
如果设置了InlineQosFlag,则inlineQos元素包含覆盖RTPS Writer的QoS值,应用于处理更新。有关可能的内联QoS参数的完整列表,请参见表8.80。
如果设置了NonStandardPayloadFlag,则serializedPayload元素的格式不符合第10节的规定。此标志是信息性的。它指示SerializedPayload已按照另一规范描述的方式进行转换。例如,在DDS-Security规范中描述的方式进行转换时,应设置此标志。
写入者通过其GUID唯一标识。通过接收者的状态获取写入者GUID:
writerGUID = { Receiver.sourceGuidPrefix, Data.writerId }
读取者通过其GUID唯一标识。通过接收者的状态获取读取者GUID:
readerGUID = { Receiver.destGuidPrefix, Data.readerId }
Data.readerId可以是ENTITYID_UNKNOWN,此时Data应用于由GuidPrefix_t Receiver.destGuidPrefix标识的参与者内该writerGUID的所有读取者。
8.3.7.3 DataFrag
此子消息从RTPS Writer发送到RTPS Reader。
8.3.7.3.1 目的
DataFrag子消息通过允许将serializedData分段并作为多个DataFrag子消息发送,扩展了Data子消息。然后,RTPS Reader通过重新组装DataFrag子消息中包含的片段。
除了Data子消息之外定义独立的DataFrag子消息,具有以下优势:
-
将每个子消息的内容和结构的变化保持最小。这使得协议的实现更加高效,因为网络数据包的解析变得简化。
-
避免在Data子消息中添加作为内联QoS参数的分段信息。这不仅可能降低性能,而且使得在线调试更加困难,因为不再明显数据是否被分段以及哪个消息包含哪个片段。
8.3.7.3.2 内容
构成DataFrag子消息结构的元素在下表中描述。
Table 8.36 – DataFrag子消息的结构
元素 | 类型 | 含义 |
EndiannessFlag | SubmessageFlag | 出现在Submessage头标志中。指示字节序。 |
InlineQosFlag | SubmessageFlag | 出现在Submessage头标志中。向Reader指示包含QoS参数的ParameterList的存在,应用于解释消息。 |
NonStandardPayloadFlag | SubmessageFlag | 出现在Submessage头标志中。向Reader指示serializedPayload子消息元素的格式不符合第10节的规定。 |
KeyFlag | SubmessageFlag | 出现在Submessage头标志中。向Reader指示dataPayload子消息元素包含数据对象键的序列化值。 |
readerId | EntityId | 标识正在通知数据对象变化的RTPS Reader实体。 |
writerId | EntityId | 标识对数据对象进行更改的RTPS Writer实体。 |
writerSN | SequenceNumber | 为由writerGuid标识的RTPS Writer进行的所有更改唯一标识更改和相对顺序。每个更改都有一个连续的序列号。每个RTPS Writer都维护其自己的序列号。 |
fragmentStartingNum | FragmentNumber | 表示serializedData中系列片段的起始片段。片段编号从1开始。 |
fragmentsInSubmessage | ushort | 此Submessage中包含的连续片段的数量,从fragmentStartingNum开始。 |
dataSize | ulong | 在分段之前的原始数据的总大小(以字节为单位)。 |
fragmentSize | ushort | 每个单独片段的大小(以字节为单位)。最大片段大小等于64K。 |
inlineQos | ParameterList | 仅当InlineQosFlag在头中设置时出现。包含可能影响消息解释的QoS。 |
serializedPayload | SerializedPayload | 一系列连续的片段,从fragmentStartingNum开始,总共fragmentsInSubmessage。代表数据对象更改后的新值的一部分。 • 如果KeyFlag未设置,则它包含数据对象更改后新值的一系列连续片段。 • 如果KeyFlag被设置,则它包含消息引用的数据对象键的一系列连续片段。 在任一情况下,连续的片段集包含fragmentsInSubmessage片段,并以由fragmentStartingNum标识的片段开始。 |
8.3.7.3.3有效性
当以下任一条件成立时,此子消息无效:
• Submessage头中的submessageLength太小。
• writerSN.value不是严格正数(1, 2, ...),或为SEQUENCENUMBER_UNKNOWN。
• fragmentStartingNum.value不是严格正数(1, 2, ...),或超过总片段数(见下文)。
• fragmentSize超过dataSize。
• serializedData的大小超过fragmentsInSubmessage * fragmentSize。
• inlineQos无效。
8.3.7.3.4接收者状态的变化
无
8.3.7.3.5逻辑解释
DataFrag子消息通过允许将serializedData分段并作为多个DataFrag子消息发送,扩展了Data子消息。一旦RTPS Reader重新组装了serializedData,DataFrag子消息的解释与Data子消息相同。以下是使用DataFrag子消息中的信息重新组装serializedData的方法。
要重新组装的数据的总大小由dataSize给出。每个DataFrag子消息在其serializedData元素中包含此数据的一个连续段。段的大小由serializedData元素的大小确定。在重新组装过程中,每个段的偏移量由:
(fragmentStartingNum - 1)* fragmentSize
确定。当接收到所有片段时,数据将完全重新组装。期望的总片段数等于:
(dataSize / fragmentSize)+((dataSize%fragmentSize)?1:0)
请注意,每个DataFrag子消息可能包含多个片段。RTPS Writer将基于所有底层传输支持的最小消息大小选择fragmentSize。如果可以通过支持较大消息的传输到达某些RTPS Reader,则RTPS Writer可以将多个片段打包到单个DataFrag子消息中,甚至可能发送常规Data子消息,如果不再需要分段。有关更多详细信息,请参见8.4.14.1。
在使用DataFrag子消息发送inlineQos时,只需要为给定Writer序列号的第一个DataFrag子消息发送inlineQos。对于给定的Writer序列号,将相同的inlineQos与每个DataFrag子消息一起发送是多余的。
8.3.7.4 Gap
8.3.7.4.1 目的
此子消息从RTPS Writer发送到RTPS Reader,向RTPS Reader指示一系列序列号不再相关。该集合可以是一系列连续的序列号或一组特定的序列号。
8.3.7.4.2 内容
构成Gap消息结构的元素在下表中描述。
表8.37 - Gap子消息的结构
元素 | 类型 | 含义 |
EndiannessFlag | SubmessageFlag | 出现在Submessage头标志中。指示字节序。 |
GroupInfoFlag | SubmessageFlag | 出现在Submessage头标志中。指示发送者所属的写入者组(Writer Group)的附加信息的存在。 |
readerId | EntityId | 标识正在通知一系列序列号不再相关的Reader实体。 |
writerId | EntityId | 标识适用于序列号范围的Writer实体。 |
gapStart | SequenceNumber | 标识不相关序列号间隔中的第一个序列号。 |
gapList | SequenceNumberSet | 具有两个目的: (1) 标识不相关序列号间隔中的最后一个序列号。 (2) 标识一系列额外的不相关序列号。 |
gapStartGSN | SequenceNumber | 仅当GroupInfoFlag在头中设置时出现。标识与由gapStart标识的样本相对应的组序列号。 |
gapEndGSN | SequenceNumber | 仅当GroupInfoFlag在头中设置时出现。标识从gapStartGSN开始的一系列不可用于Reader的GSN的结束。它应大于或等于由gapList.bitmapBase标识的样本的组序列号。 |
8.3.7.4.3 有效性
当以下任一条件成立时,此子消息无效:
• Submessage头中的submessageLength太小。
• gapStart为零或负值。
• gapList无效(如8.3.5.5中定义)。
如果GroupInfoFlag被设置,并且:
• gapStartGSN.value为零或负值
• gapEndGSN.value为零或负值
• gapEndGSN.value < gapStartGSN.value-1
8.3.7.4.4 接收者状态的变化
无
8.3.7.4.5 逻辑解释
RTPS Writer向RTPS Reader发送Gap消息,以通知某些序列号不再相关。这通常是由于Writer端对样本的过滤(内容过滤主题、基于时间的过滤)引起的。在这种情况下,新数据值可能会替换Gap中标记为不相关的序列号所代表的数据对象的旧值。
Gap消息传达的不相关序列号由两个组成:
-
所有范围内的序列号gapStart <= sequence_number <= gapList.base -1
-
所有明确列在gapList中的序列号。
这组将被称为Gap::irrelevant_sequence_number_list。 Writer通过使用接收者的状态获取Writer GUID,以唯一标识Writer。
writerGUID = { Receiver.sourceGuidPrefix, Gap.writerId }
通过使用接收者的状态获取Reader GUID,以唯一标识Reader。
readerGUID = { Receiver.destGuidPrefix, Gap.readerId }
Writer设置GroupInfoFlag以指示存在gapStartGSN和gapEndGSN元素。这些字段提供与属于Writer组的Writers的CacheChanges相关的信息。有关DDS如何使用此功能的详细信息,请参见8.7.6节。 在某些情况下,gapEndGSN可以延伸到对应于gapList.bitmapBase的组序列号之外,其中这些额外的组序列号是由其他Writers编写的。
8.3.7.5 心跳
8.3.7.5.1 目的
该消息从RTPS Writer发送到RTPS Reader,以通知Reader Writer可用的更改的序列号。
8.3.7.5.2 内容
构成Heartbeat消息结构的元素在下表中描述。
表8.38 - 心跳子消息的结构
元素 | 类型 | 含义 |
EndiannessFlag | SubmessageFlag | 出现在Submessage头标志中。指示字节序。 |
FinalFlag | SubmessageFlag | 出现在Submessage头标志中。指示Reader是否需要响应Heartbeat,还是仅为了提供建议性的心跳。 |
LivelinessFlag | SubmessageFlag | 出现在Submessage头标志中。指示与消息的RTPS Writer相关联的DDS DataWriter是否已手动断言其LIVELINESS。 |
GroupInfoFlag | SubmessageFlag | 出现在Submessage头标志中。指示发送者所属的写入者组(Writer Group)的附加信息的存在。 |
readerId | EntityId | 标识正在通知一系列序列号可用性的Reader实体。可以设置为ENTITYID_UNKNOWN,以表示发送消息的Writer的所有读者。 |
writerId | EntityId | 标识适用于序列号范围的Writer实体。 |
firstSN | SequenceNumber | 如果Writer中有样本可用,则标识Writer中可用的第一个(最低)序列号。 如果Writer中没有可用的样本,则标识Writer尚未写入的最低序列号。 |
lastSN | SequenceNumber | 标识Writer曾经写入的最后(最高)序列号。 |
count | Count | 每次发送新的Heartbeat消息时递增的计数器。 为Reader提供检测重复Heartbeat消息的手段,这可能是由于冗余通信路径的存在而导致的。 |
currentGSN | SequenceNumber | 仅当GroupInfoFlag在头中设置时出现。标识在发送HeartBeat时Writer组中任何DataWriter编写的最后(最高)组序列号。 |
firstGSN | SequenceNumber | 仅当GroupInfoFlag在头中设置时出现。标识与序列号firstSN相对应的样本的组序列号。 |
lastGSN | SequenceNumber | 仅当GroupInfoFlag在头中设置时出现。标识与序列号lastSN相对应的样本的组序列号。 |
writerSet | GroupDigest | 仅当GroupInfoFlag在头中设置时出现。标识属于Writer组的时间样本currentGSN被编写时Writer组的子集。 |
secureWriterSet | GroupDigest | 仅当GroupInfoFlag在头中设置时出现。保留供DDS-Security规范使用。 |
以下示例说明了在各种情况下如何分配firstSN.value和lastSN.value。
示例1. 在发送Heartbeat之前从未写入任何样本的Writer将发送一个firstSN.value = 1,lastSN.value = 0的Heartbeat。
示例2. 仅在其缓存中具有一个具有序列号SN的样本的Writer将发送一个firstSN.value = lastSN.value = SN的Heartbeat。
示例3. 已经写入10个样本且仍然在其缓存中具有最后5个样本的Writer将发送一个firstSN.value = 6,lastSN.value = 10的Heartbeat。
示例4. 在发送Heartbeat之前写入了10个样本但在Heartbeat时没有任何样本可用的Writer将发送一个firstSN.value = 11,lastSN.value = 10的Heartbeat。
8.3.7.5.3 有效性
当以下任一情况为真时,此Submessage无效:
• Submessage头中的submessageLength太小
• firstSN.value为零或负值
• lastSN.value为负值
• lastSN.value < firstSN.value - 1
如果设置了GroupInfoFlag且:
• currentGSN.value为零或负值
• firstGSN.value为零或负值
• lastGSN.value为负值
• lastGSN.value < firstGSN.value - 1
• currentGSN.value < firstGSN.value
• currentGSN.value < lastGSN.value
8.3.7.5.4 Receiver状态的变化
无
8.3.7.5.5 逻辑解释
Heartbeat消息有两个目的:
-
它通知Reader写入者的HistoryCache中可用的序列号,以便Reader可以通过AckNack请求任何它错过的序列号。
-
它请求Reader为已经输入到Reader的HistoryCache的CacheChange更改发送确认,以便Writer知道Reader的状态。
所有Heartbeat消息都用于第一个目的。也就是说,Reader将始终了解Writer的HistoryCache的状态,并可能请求它错过的内容。通常,只有在RTPS Reader缺少CacheChange时,它才会发送AckNack消息。
Writer使用FinalFlag请求Reader为其接收到的序列号发送确认。如果Heartbeat设置了FinalFlag,则不需要Reader发送AckNack消息回来。但是,如果未设置FinalFlag,则Reader必须发送AckNack消息,指示它已接收到Writer的HistoryCache中的所有CacheChange更改。
Writer设置LivelinessFlag以指示与消息的RTPS Writer相关联的DDS DataWriter已经通过适当的DDS操作(请参阅DDS规范)手动断言其活跃期限。因此,RTPS Reader应更新相应远程DDS DataWriter的手动活跃期限。
Writer设置GroupInfoFlag以指示currentGSN、firstGSN、lastGSN、writerSet和secureWriterSet元素的存在。这些字段提供了属于Writer组的Writers的CacheChanges的关联信息。有关DDS如何使用此功能,请参见8.7.6。
通过Receiver的状态唯一标识Writer。Writer GUID是使用Receiver的状态获取的:
writerGUID = { Receiver.sourceGuidPrefix,Heartbeat.writerId }
通过Receiver的状态唯一标识Reader。Reader GUID是使用Receiver的状态获取的:
readerGUID = { Receiver.destGuidPrefix,Heartbeat.readerId }
Heartbeat.readerId可以是ENTITYID_UNKNOWN,此时Heartbeat适用于Participant内具有writerGUID的所有Readers。
8.3.7.6 HeartbeatFrag
8.3.7.6.1 目的
在分段数据并在所有片段可用之前,HeartbeatFrag Submessage从RTPS Writer发送到RTPS Reader,以通知Writer有哪些片段可用。这使得在片段级别上实现可靠的通信。
一旦所有片段都可用,将使用常规的Heartbeat消息。
8.3.7.6.2 内容
形成HeartbeatFrag消息结构的元素如下表所示。
元素 | 类型 | 意义 |
EndiannessFlag | SubmessageFlag | 出现在Submessage头部的标志中。指示字节顺序。 |
readerId | EntityId | 标识正在被通知有片段可用的Reader实体。可以设置为ENTITYID_UNKNOWN,表示该消息适用于发送消息的Writer的所有Reader。 |
writerId | EntityId | 标识发送Submessage的Writer实体。 |
writerSN | SequenceNumber | 标识具有可用片段的数据更改的序列号。 |
lastFragmentNum | FragmentNumber | Writer上为标识由writerSN确定的更改而可用的所有片段,包括此最后(最高)片段。 |
count | Count | 每次发送新的HeartbeatFrag消息时递增。提供一种方式,使Reader能够检测由于冗余通信路径的存在而导致的重复HeartbeatFrag消息。 |
8.3.7.6.3 有效性
当以下情况之一为真时,此子消息无效:
• 子消息头中的 submessageLength 过小。
• writerSN.value 为零或负值。
• lastFragmentNum.value 为零或负值。
8.3.7.6.4 接收器状态变化
无
8.3.7.6.5 逻辑解释
HeartbeatFrag 消息的目的与常规 Heartbeat 消息相同,但它不是指示一系列序列号的可用性,而是指示具有序列号 WriterSN 的数据更改的片段范围的可用性。
RTPS Reader将通过发送 NackFrag 消息来响应,但仅在缺少任何可用片段时才会响应。通过接收器状态,可以唯一确定Writer。Writer的 GUID 是使用接收器的状态获得的:
writerGUID = { Receiver.sourceGuidPrefix, HeartbeatFrag.writerId }
Reader通过接收器的状态唯一标识。 Reader的 GUID 是使用接收器的状态获得的:
readerGUID = { Receiver.destGuidPrefix, HeartbeatFrag.readerId }
HeartbeatFrag.readerId 可以是 ENTITYID_UNKNOWN,此时 HeartbeatFrag 适用于 Participant 中具有该 Writer GUID 的所有 Readers。
8.3.7.7 InfoDestination
8.3.7.7.1 目的
此消息从 RTPS Writer发送到 RTPS Reader,以修改在其后出现的子消息中用于解释 Reader entityIds 的 GuidPrefix。
8.3.7.7.2 内容
形成 InfoDestination 消息结构的元素在下表中描述。
表 8.40 - InfoDestination 子消息的结构
元素 | 类型 | 含义 |
EndiannessFlag | SubmessageFlag | 出现在子消息头标志中。指示字节序。 |
guidPrefix | GuidPrefix | 提供应用于重建在其后的子消息中出现的所有 RTPS Reader 实体的 EntityIds 的 GUID 的 GuidPrefix。 |
8.3.7.7.3 有效性
当以下任一情况为真时,此子消息无效:
• 子消息头中的 submessageLength 太小。
8.3.7.7.4 Receiver 状态的变化
if (InfoDestination.guidPrefix != GUIDPREFIX_UNKNOWN)
{ Receiver.destGuidPrefix = InfoDestination.guidPrefix }
else { Receiver.destGuidPrefix = <GuidPrefix_t of the Participant receiving the_message> }
8.3.7.7.5 逻辑解释
无
8.3.7.8 InfoReply
8.3.7.8.1 目的
此消息从 RTPS Reader 发送到 RTPS Writer。它包含关于在同一消息中其后的 Submessages 的回复应发送到何处的明确信息。
8.3.7.8.2 内容
构成 InfoReply 消息结构的元素如下表所述。
Table 8.41 - InfoReply 子消息的结构
元素 | 类型 | 意义 |
EndiannessFlag | SubmessageFlag | 出现在 Submessage 头标志中。指示字节顺序。 |
MulticastFlag | SubmessageFlag | 出现在 Submessage 头标志中。指示 Submessage 是否还包含多播地址。 |
unicastLocatorList | LocatorList | 指示在回复其后的 Submessages 时,Writer 应使用的替代单播地址集。 |
multicastLocatorList | LocatorList | 指示在回复其后的 Submessages 时,Writer 应使用的替代多播地址集。只有在设置 MulticastFlag 时才出现。 |
8.3.7.8.3 有效性
当以下任一条件为真时,此 Submessage 无效:
-
在 Submessage 头中,submessageLength 过小。
8.3.7.8.24 接收者状态变更
Receiver.unicastReplyLocatorList InfoReply.unicastLocatorList
if ( MulticastFlag )
{ Receiver.multicastReplyLocatorList = InfoReply.multicastLocatorList }
else { Receiver.multicastReplyLocatorList = <empty> }
8.3.7.8.5 逻辑解释
无
8.3.7.9 InfoSource
8.3.7.9.1 目的
此消息修改其后 Submessages 的逻辑源。
8.3.7.9.2 内容
下表描述了构成 InfoSource 消息结构的元素。
表8.42 - InfoSource 子消息结构
元素 | 类型 | 含义 |
EndiannessFlag | SubmessageFlag | 出现在 Submessage 标头标志中,指示字节序。 |
protocolVersion | ProtocolVersion | 指示后续 Sudmessages 使用的协议版本。 |
vendorId | VendorId | 指示产生后续 Submessages 的厂商的 VendorId。 |
guidPrefix | GuidPrefix | 标识包含后续 Submessages 源的 RTPS Writer 实体的 Participant。 |
8.3.7.9.3 有效性
当以下任一条件为真时,此子消息无效:
• Submessage 头部的 submessageLength 过小。
8.3.7.9.4 Receiver 状态的变化
Receiver.sourceGuidPrefix = InfoSource.guidPrefix
Receiver.sourceVersion = InfoSource.protocolVersion
Receiver.sourceVendorId = InfoSource.vendorId
Receiver.unicastReplyLocatorList = { LOCATOR_INVALID }
Receiver.multicastReplyLocatorList = { LOCATOR_INVALID }
haveTimestamp = false
8.3.7.9.5 逻辑解释
无
8.3.7.10 信息时间戳 (InfoTimestamp)
8.3.7.10.1 目的
此子消息用于发送一个时间戳,该时间戳适用于随后在同一消息中的子消息。
8.3.7.10.2 内容
下表描述了构成 InfoTimestamp 消息结构的元素。
Table 8.43 – InfoTimestamp 子消息结构
元素 | 类型 | 含义 |
EndiannessFlag | SubmessageFlag | 出现在子消息头标志中。指示字节顺序。 |
InvalidateFlag | SubmessageFlag | 指示是否应将随后的子消息视为具有时间戳。 |
timestamp | Timestamp | 仅当头部的 InvalidateFlag 未设置时出现。包含应用于解释随后子消息的时间戳。 |
8.3.7.10.2有效性
当以下条件成立时,此子消息无效:
• 子消息头的 submessageLength 过小。
8.3.7.10.2接收者状态变化
if(!InfoTimestamp.InvalidateFlag)
{ Receiver.haveTimestamp = true
Receiver.timestamp = InfoTimestamp.timestamp }
else { Receiver.haveTimestamp = false }
8.3.7.10.2 逻辑解释
无
8.3.7.11 NackFrag
8.3.7.11.1 目的
NackFrag 子消息用于将Reader的状态传达给写入器。当数据更改被作为一系列片段发送时,NackFrag 子消息允许读取器通知Writer有关仍然缺失的特定片段编号。
此子消息只能包含负面确认。请注意,这与 AckNack 子消息不同,后者包括正面和负面确认。这种方法的优点包括:
• 它消除了 AckNack 子消息引入的窗口限制。由于 SequenceNumberSet 的大小限制为 256,因此 AckNack 子消息仅限于 Nack 那些其序列号不超过第一个缺失样本的序列号的样本。低于第一个缺失样本的任何样本都将被确认。另一方面,NackFrag 子消息可用于 Nack 任何片段编号,甚至是比在较早的 AckNack 子消息中 Nack 的片段相隔超过 256 的片段。在处理包含大量片段的样本时,这变得很重要。
• 片段可以以任何顺序被否定确认。
8.3.7.11.1内容
下表描述了构成 NackFrag 消息结构的元素。
Table 8.44 - NackFrag 子消息的结构
元素 | 类型 | 含义 |
EndiannessFlag | SubmessageFlag | 出现在子消息头标志中, 指示字节序。 |
readerId | EntityId | 标识请求接收特定片段的Reader实体。 |
writerId | EntityId | 标识 NackFrag 消息的目标Writer实体。这是被要求重新发送某些片段的Writer实体。 |
writerSN | SequenceNumber | 某些片段丢失的序列号。 |
fragmentNumberState | FragmentNumberSet | 将Reader的状态传达给Writer。集合中出现的片段编号指示读取器端缺失的片段。未出现在集合中的片段状态不确定(可能已接收,也可能未接收)。 |
count | Count | 每次发送新的 NackFrag 消息时递增的计数器。 为Writer检测重复 NackFrag 消息提供手段,这可能是由于冗余通信路径的存在而导致的。 |
8.3.7.11.3 有效性
当以下任一条件为真时,此子消息无效:
• 子消息头中的 submessageLength 过小。
• writerSN.value 为零或负数。
fragmentNumberState 无效(如 8.3.5.7 中定义)。
8.3.7.11.4接收器状态变化
无
8.3.7.11.5逻辑解释
读取器通过 NackFrag 消息向写入器请求片段。
写入器通过其 GUID 唯一标识。写入器 GUID 是使用接收器的状态获得的:
writerGUID = { Receiver.destGuidPrefix, NackFrag.writerId }
读取器通过其 GUID 唯一标识。读取器 GUID 是使用接收器的状态获得的:
readerGUID = { Receiver.sourceGuidPrefix, NackFrag.readerId }
请求片段的序列号由 writerSN 给出。显式表示片段编号的机制取决于 PSM。通常,使用紧凑的表示(如位图)。
8.3.7.12 填充
8.3.7.12.1 目的
此子消息的目的是允许引入任何必要的填充,以满足任何所需的内存对齐要求。它没有其他含义。
8.3.7.12.2 内容
此子消息没有内容。它仅通过子消息头部分实现其目的。填充量由 submessageLength 的值确定。
8.3.7.12.3 有效性
此子消息始终有效。
8.3.7.12.4 接收器状态变化
无
8.3.7.12.5 逻辑解释
无