DDS-XRCE协议阅读翻译

最近在研究Micro-ROS的底层通讯机制的时候,了解到使用的是DDS-XRCE协议,所以转而来研究阅读这个协议的相关内容。这部分国内还没有多少人重视,鲜有人对相关部分进行翻译,所以准备将这个协议进行一下翻译理解。

DDS-XRCE

1 scope

XRCE协议是一个用于资源受限低能耗设备(作为客户端)和一个Agent(作为服务端)之间的协议。XRCE协议允许设备通过一个中间服务(XRCE Agent)来和一个DDS网络进行通信并且在一个DDS域中发布、订阅话题。
(XRCE协议是一个资源受限设备(client)和一个XRCE Agent(server)之间的客户端-服务器协议。协议允许周期性睡眠唤醒的资源受限设备在有限带宽网络上访问DDS全局数据空间)

4 术语和定义

  • DDS
    数据分发服务,独立于实现语言
  • DDS Domain
    全局数据空间,是主题和类型定义的逻辑范围,每一个域由唯一的域id标识,域之间相互独立,两个DDS应用只有加入相同域才可以通信
  • DDS DomainParticipant
    应用程序用于加入DDS域的DDS实体.采用工厂模式生成实体,一个实体可以加入一个域。
  • DDS Global Data Space
    由通过DDS进行通信的双方以及他们的可见数据组成
  • GUID
    全局唯一标识

5 符号解释

  • DDS
    数据分发服务
  • IDL
    接口定义语言
  • RTPS
    实时发布订阅
  • XRCE
    极端受限资源环境

7 XRCE Object Model

7.1 General

如上文所言,DDS-XRCE协议是一种用于XRCE Client 和 XRCE Agent之间的有线协议。XRCE Agent是一个DDS全局数据空间中的DDS参与者。DDS-XRCE协议允许客户端通过XRCE Agent作为一个代理从而可以在DDS全局数据空间中产生和消费数据。

为了对XRCE Client和XRCE Agent之间的交互关系进行建模,规范定义了XRCE的UML模型,也就是DDS-XRCE Object Model,来定义agent需要实现的对象、接口和操作,同时还定义了Agent和DDS规范中的标准DDS Object Model的操作的关联。

由于目标环境是资源受限设备,DDS-XRCE Object Model并不完全等同于Standard DDS Object Model。它更关注其使能DDS-XRCE客户端以一种有意义的方式参与DDS数据空间的需求。除了标准DDS对象模型中的公开对象外,DDS-XRCE对象模型还定义了管理断开连接的客户端以及启用访问控制和访问权限所需的新对象

为了在资源受限设备上运行,XRCE-DDS Object Model主要是在Standard DDS Object Model上做减法,但是它也增加了一些支持远程客户端的特性,如访问控制模型(access control model)和应用程序管理模型(application management model)

总之尽管更简单,DDS-XRCE Object Model仍为客户端提供了对DDS全局数据空间完整的访问。任何DDS上的DDS Topic都可以使用任何QoS策略被发布或者订阅。

7.2 XRCE Client

DDS-XRCE客户端(XRCE客户端)向DDS-XRCE对象模型和façade object公开。

出于以下三种原因,DDS Objectg Model和它的操作没有直接运用在本协议

  1. DDS Object Model的设计初衷是和本地编程API一起使用,所以包含了很多具有强类型参数的对象和方法以及通过应用程序向中间件注册的侦听器对象的直接回调接口。这种是不适用于资源受限的低功耗客户端,这些客户端需要的是一个没有回调简单接口,并且希望使用文本方式编码的参数
  2. ==由于可能会使用低功耗模式和深度睡眠来节省电池或失去无线电连接,因此XRCE客户端连接先天性间断的特性。 DDS-XRCE DDS Object Model必须通过引入“session”来克服间歇性连接,“会话”可以存在于设备重复的睡眠-唤醒周期中。==
  3. xrce客户端可以在任何地方访问dds服务 所以一个来证明验证每个客户端的应用/主体的访问控制模块是很有必要的。这个模型控制主体是否可以访问DDS全局数据空间以及每个主体可以执行哪些操作(可以往哪个topic进行发布订阅)

    XRCE-DDS为4种不同需求的客户端提供支持。

设备 功能
简单设备 简单设备可能不需要与XRCE Agent执行任何发现交互,除了(a)由Agent检测到它们的存在,(b)在DDS数据空间中建立,以及(c)能够使用DDS QoS策略发布已知的DDS主题的数据。这样的客户机不需要DDS的任何QoS配置和动态实体创建功能。
更有能力的设备 更有能力的设备可能需要发布和订阅已知的主题;然而,XRCE Client可能不希望数据在任意时间由XRCE Agent推送,例如由于网络限制。因此,将数据从作者“推”给读者的DDS模型可能无法很好地工作。本规范通过允许设备从Agent激活/停用“数据推送”来解决此限制
进一步的客户端 高级Client可以选择利用DDS概念并创建自己的XRCEAgent资源,这些资源映射到DDS对象。这些Client还可能希望控制DDS对象的Qos。此规范通过公开一组动态创建/更新/删除代理对象的操作来启用这些类型的Client。Agent/Client的这种处理方式与前两种情况形成对比,在前两种情况下,所有资源都是预先知道的,并且在Agent上预先配置好的
复杂设备 最后,复杂Client可能需要了解高级概念,例如序列号(或样本id)、时间戳和DDS源。

7.3 XRCE Agent

DDS-XRCE Agent的目的就是建立并维护XRCE Client在DDS数据空间的存在。本规范描述了在对象模型上的一系列操作

一个重要的性质就是简化了和XRCE Agent的互动。Agent表示了一个描述resources的对象模型。在一个高的层次,资源是可以用名称访问的对象,并且具有属性和行为。资源可以用都知道的名字提前定义,或者被XRCE Client动态创建。这些XRCE Agent中的资源比如XRCE Type、XRCE DataWriter、XRCE DataReader。任何被允许与XRCE Agent通信并具有所需访问权限的XRCE Client都可以按名称引用这些资源进行使用,而不用自己再创建这样一个资源。

DDS-XRCE Object Model的一个重要特性就是Client能够查询Model的能力,而不是像Standard DDS Object Model中的典型行为,后者可以实时更新、推送修改。那样的模型可能不适用于设备经常性断开的目标环境。==该协议使Client能够负责何时数据接收,并且请求XRCE Agent来返回符和一系列约束的数据。如此,一个XRCE Client就不会在断开期间被一个XRCE Agent唤醒,相反,Client会在唤醒后查询XRCE Agent==

XRCE Agent不必暴露任何编程API,它使用DDS-XRCE协议和XRCE Client进行标准交互,同时使用DDS-RTPS协议和其他DDS域进行交互。

7.4 Model Overview

从一个比较高的层面来看,DDS-XRCE Object Model包括五个类:Root单例、ProxyClientApplicationAccessControllerDomainParticipant

image-20211101160913220

Root

Root单例是服务的入口点。它用作由XRCE Agent管理的所有对象的工厂

ProxyClient

ProxyClient类对使用XRCE协议与XRCE Agent进行交互的XRCE Client应用程序进行建模。 每个Application对象都与单个XRCE ProxyClient关联,并从分配给XRCE Client的访问权限中获取其访问权限。

Application

Application类对与XRCE客户端连接,并管理在一个或多个DDS域上发布和订阅数据所需的DDS对象进行管理的软件应用程序进行建模。 XRCE应用程序可以与零个或多个DomainParticipant对象相关联

AccessController

AccessController负责做出有关允许特定XRCE ProxyClient执行的资源和操作的决策。 它包含将客户端与特权相关联的规则,这些规则确定代表客户端执行的应用程序可以加入哪个DDS域,该应用程序可以读取和写入的DDS主题,等等。

DomainParticipant

DDS-XRCE DomainParticipant是DDS DomainParticipant的代理,对与DDS域的关联以及应用程序在该域上发布和订阅主题的能力进行建模。

7.5 XRCE DDS Proxy Objects

几个DDS-XRCE对象充当相应DDS对象的代理。委派实际的DDS行为和DDS-RTPS协议实现给DDS对象的代理,从而允许Client的应用程序以一级用户的身份参与DDS网络。

image-20211101160940205

7.6 XRCE Object Identification

代表特定XRCE客户端的XRCE代理管理的每个XRCE对象都通过ObjectId进行标识,也就是说,ObjectId和ClientKey的范围应该是统一的,在代理中。特定对象的ObjectId值应在XRCE代理上配置或者由XRCE客户端在创建代理时确定。

两个ObjectId被保留了,分别是无效的对象(OBJECTID_INVALID),值为{0x00,0x00},以及XRCE ProxyClient对象(OBJECTID_CLIENT),值为{0xFF,0xFF}。

对象也可以被字符串resourceName所标识,这个名称的格式由资源决定,并且提供了一种使用配置文件或其他在代理上配置资源的方式。

7.7 对XRCE Object上的操作进行建模所用到的数据类型

XRCE object上的操作接收参数,这些参数的格式由一套IDL数据类型进行描述。这些IDL描述不仅在XRCE Object操作的描述上被使用,也同样用来定义clilent和agent之间信息交换的有线表示。

数据类型的IDL定义在Annex A IDL Types中明确。当把这些类型序列化为二进制表示时,编码应该遵循在《DDS-XTYPES》中的规则

7.7.1 Data and Samples

当XRCE Agent发送数据给XRCE Client时,他会使用1-5种可能的格式,这些格式根据是否数据仅仅自己单独发送还是伴随着元数据如时间戳、序列号等等发送而有所不同。

当然这些可以合并为一个形如联合(union)类型,但这样做会给序列化带来更大的开销,在带宽受限的环境下,这种开销是不希望有的。

5种可能的描述为:SampleData, Sample, SampleDataSeq, SampleSeq和SamplePackedData 。它们分别是变量FORMAT_DATA,
FORMAT_DATA_SEQ, FORMAT_SAMPLE, FORMAT_SAMPLE_SEQ和FORMAT_PACKED的格式。

所有这些表示形式都使用[DDS-XTYPES]中定义的XCDR表示形式对数据进行序列化。 例如,SampleData的定义由IDL给出:

1
2
3
4
@extensibility(FINAL)
struct SampleData {
XCDRSerializedBuffer serialized_data;
};

在这个结构中,XCDRSerializedBuffer结构表示了通过序列化使用DDS-XTYPES条款7.4中定义的XCDR版本2规则发送的特定于应用程序的数据类型而得到的字节。

其他的格式可能包含有其他信息,但是他们都依赖于SampleData来保存序列化特定于应用程序的数据。比如数据格式FORMAT_SAMPLE使用了Sample的定义如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@bit_bound(8)
bitmask SampleInfoFlags {
@position(0) INSTANCE_STATE_UNREGISTERED, //
@position(1) INSTANCE_STATE_DISPOSED, //
@position(2) VIEW_STATE_NEW, //
@position(3) SAMPLE_STATE_READ, //
};
@extensibility(FINAL)
struct SampleInfo {
SampleInfoFlags state; //结合了SampleState, InstanceState, ViewState
unsigned long sequence_number;
unsigned long session_time_offset; // 上限到53天的毫秒计时
};
@extensibility(FINAL)
struct Sample {
SampleInfo info;
SampleData data;
};

包含示例信息的最紧凑的DataFormat是FORMAT_PACKED。 此格式使用以下定义的IDL类型PackedSamples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
typedef unsigned short DeciSecond; // 1/10 秒
@extensibility(FINAL)
struct SampleInfoDelta {
SampleInfoFlags state; // 结合了 SampleState, InstanceState, ViewState
octet seq_number_delta;
DeciSecond timestamp_delta; // 1/10秒为单位
};
@extensibility(FINAL)
struct SampleDelta {
SampleInfoDelta info_delta;
SampleData data;
};
@extensibility(FINAL)
struct PackedSamples {
SampleInfo info_base;
sequence<SampleDelta> sample_delta_seq;
};

7.7.2 DataRepresentation

DataRepresentation类型用于保存data samples的值以及附加sample信息,例如序列号或时间戳。 XRCE ProxyClient的write操作使用它。

DataRepresentation定义为由DataFormat区分的联合。 根据区分符,它选择第7.7.1节中定义的格式之一。

下表1中介绍了DataFormat的可能值和所得表示形式

DataFormat 选择的DataRepresentatoin
FORMAT_DATA 包含单个sample的信息,没有附加sample信息
FORMAT_DATA_SEQ 包含一系列data sample。 每个data sample仅包含data,而没有附加sample信息
FORMAT_SAMPLE 包含单个sample的信息,也包含附加sample的信息(SampleInfo)。SampleInfo包含相应DDS Sample的DDS InstanceState,SampleState和ViewState。 它还包含样本序列号和时间戳。 时间戳表示为相对于创建会话时建立的会话时间戳的偏移量。 会话时间戳对应于CLIENT_Representation中的client_timestamp属性;
FORMAT_SAMPLE_SEQ 包含一系列的samples,每个data sample包含了data和附加的sample信息
FORMAT_PACKED 包含一系列样本,每个样本同时包含数据和其他样本信息,但使用的样本比SampleSeq更为紧凑。
此表示仅限于序列号(相距不超过256个)和时间戳(100分钟)接近的样本。 它还使用较低分辨率(1/10秒)的时间戳。
PackedSamples类型包含一个公共的SampleInfo(info_base)和一个SampleDelta序列。 每个SampleDelta包含一个SampleData以及一个关联的SampleInfoDelta(info_delta)
每个样本的SampleInfo应通过将公共info_base与对应于该sample的info_delta相结合来计算。 所得的SampleInfo(resulting_info)定义为:
$resulting_info.state := info_delta.stateresulting_info.session_time_offset := info_base.session_time_offset + info_delta.timestamp_delta$

DataRepresentation类型被定义为:

1
2
3
4
5
6
7
8
9
10
11
12
13
@extensibility(FINAL)
union DataRepresentation switch(DataFormat) {
case FORMAT_DATA:
SampleData data;
case FORMAT_SAMPLE:
Sample sample;
case FORMAT_DATA_SEQ:
SampleDataSeq data_seq;
case FORMAT_SAMPLE_SEQ:
SampleSeq sample_seq;
case FORMAT_PACKED_SAMPLES:
PackedSamples packed_samples;
};

@@@

7.7.4 ObjectId

XRCE ObjectId用于保存XRCE对象的唯一标识。 每个ObjectId的作用域都是XRCE客户端和代理对。 因此,由代理管理的ObjectId值仅对于每个XRCE客户端都是唯一的。 XRCE客户端通常连接到单个XRCE代理。 在这种情况下,XRCE客户端可以将ObjectId视为全局唯一。

ObjectId在A IDL类型中定义为:

1
typedef  octet ObjectId [2];

7.7.5 ObjectKind

XRCE ObjectKind用于枚举和标识XRCE Object的类型。 XRCE对象分为14种。 可能的种类在A IDL类型中定义为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef octet ObjectKind;

const ObjectKind OBJK_INVALID = 0x00;
const ObjectKind OBJK_PARTICIPANT = 0x01;
const ObjectKind OBJK_TOPIC = 0x02;
const ObjectKind OBJK_PUBLISHER = 0x03;
const ObjectKind OBJK_SUBSCRIBER = 0x04;
const ObjectKind OBJK_DATAWRITER = 0x05;
const ObjectKind OBJK_DATAREADER = 0x06;
const ObjectKind OBJK_TYPE = 0x0A;
const ObjectKind OBJK_QOSPROFILE = 0x0B;
const ObjectKind OBJK_APPLICATION = 0x0C;
const ObjectKind OBJK_AGENT = 0x0D;
const ObjectKind OBJK_CLIENT = 0x0E;

7.7.6 ObjectIdPrefix

ObjectIdPrefix用于保存特定ObjectKind的XRCE对象的唯一标识。 对象的ObjectId由来自ObjectIdPrefix的12位和来自ObjectKind的4位组成。

ObjectIdPrefix在A IDL Types中定义为:

1
typedef octet ObjectIdPrefix [2];

假设XRCE对象具有objectid_prefix,object_kind和object_id,则满足下列关系:

7.7.7 ResultStaus

ResultStatus用于保存XRCE对象操作的返回值。它包括了包括了表示操作(operations)成功或者失败、以及失败原因的StatusValue。还包括了一个针对不同操作特殊定制的状态,用于返回供应商和一些特殊的定制消息。

StatusValue和ResultStatus在附录A中定义为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@bit_bound(8)
enum StatusValue {
@value(0x00) STATUS_OK,
@value(0x01) STATUS_OK_MATCHED,
@value(0x80) STATUS_ERR_DDS_ERROR,
@value(0x81) STATUS_ERR_MISMATCH,
@value(0x82) STATUS_ERR_ALREADY_EXISTS,
@value(0x83) STATUS_ERR_DENIED,
@value(0x84) STATUS_ERR_UNKNOWN_REFERENCE,
@value(0x85) STATUS_ERR_INVALID_DATA,
@value(0x86) STATUS_ERR_INCOMPATIBLE,
@value(0x87) STATUS_ERR_RESOURCES
};
struct ResultStatus {
StatusValue status;
octet implementation_status;
};

特殊定制的StatusValue解释如下:

StatusValue 解释
STATUS_OK 表示操作的执行成功了
STATUS_OK_MATCHED 表示针对一个resource的create或者update操作执行成功了。该resource已经存在于Agent上,并且该resource的状态已经和该操作请求的resource状态匹配。因此没有对资源进行任何实际上的修改。
STATUS_ERR_DDS_ERROR 表示操作的执行失败了,是由与该操作相关的DDS资源创建或操作时的错误引起的
STATUS_ERR_MISMATCH 表示针对一个resource的create或者update操作执行成功了。该resource已经存在于Agent上,但是该resource的状态和该操作请求的resource状态不匹配。而且无法修改resource的状态。
STATUS_ERR_ALPEADY_EXISTS 表示操作的执行失败了,因为这个resource客观上已经存在了
STATUS_ERR_DENIED 表示操作的执行失败了,因为没有权限
STATUS_ERR_UNKNOWN_REFERENCE 表示操作的执行失败了,因为引用的resource并不为Agent所知。
STATUS_ERR_INVALID_DATA 表示操作的执行失败了,因为传入的参数数据不合法
STATUS_ERR_INCOMPATIBLE 表示操作的执行失败了,因为Client和Agent不兼容
STATUS_ERR_RESOURCES 表示操作的执行失败了,因为Agent上的资源错误

7.7.8 BaseObjectRequest

BaseObjectRequest用来保存从XRCE Client发送给Agent的request的公共参数。他在附录中被定义为:

1
2
3
4
5
@extensibility(FINAL)
struct BaseObjectRequest {
RequestId request_id;
ObjectId object_id;
};

这个类型的成员说明如下:

  • request_id(RequestId):用于标识每个请求。用来将回复和请求进行相关联。适用于每对XRCE Client与Agent。注意,只要Client和Agent知道具有该值的历史请求不再活跃时,才可以为将来的请求重用request_id的值。
  • object_id(ObjectId):这就是request的目标。对于创建对象的request来说,object_id给创建的object传达了ObjectIdPrefix信息

7.7.9 BaseObjectReply

BaseObjectReply类型用来保存从XRCE Agent返回给Client的reply的公共参数。它在附录中被定义为:

1
2
3
4
5
6
7
8
9
struct ResultStatus {
StatusValue status;
octet implementation_status;
};
@extensibility(FINAL)
struct BaseObjectReply {
BaseObjectRequest related_request;
ResultStatus result;
};

类型的成员说明如下:

  • related_request包含了发送这次reply所响应的request的request_idobject_id
    • request_id(RequestId)用于标识request。它用来表述request和reply的联系
    • object_id(ObjectId)是request的目标,对于创建objects的requests来说,object_id将创建的对象所需要的objectId进行传递,在这种情况下,
  • implementation_status(8位字节)提供特定于实现(特定于供应商)的返回状态。 该值由代理的 XrceVendorId 限定。 它只能由理解返回它的代理的 XrceVendorId 的实现状态值的客户端解释。

7.8 XRCE 对象操作

7.8.1 ClientKey 的使用

所有操作都是在 ClientKey 的上下文中执行的,它用于验证和识别Client:

  • ClientKey 被分配给每个Client。 ClientKey 向特定Agent唯一标识Client。 ClientKey 与代理内Client的一组权限相关联。
  • ClientKey 应被视为机密。 它必须在Client和Agent中进行配置。 创建和配置超出了本规范的范围。
  • ClientKey无法被解释

除了 XRCE Root 上的 create_client 和 get_info 操作之外,所有其他操作都期望 ClientKey 引用一个已经存在的 XRCE ProxyClient。 如果不是这种情况,操作将失败。

为避免可能危及安全的信息泄漏,在某些情况下,无法找到 ClientKey 可能会导致 returnValue 具有 STATUS_ERR_NOCLIENT,而在其他情况下,它可能会默默地断开与客户端的连接。

==代理应维护一个计数器,记录在已建立的连接上发送 STATUS_ERR_NOCLIENT 的次数,一旦超过某个阈值,它将关闭连接。 代理随后可能会拒绝或限制源自先前关闭的同一客户端传输端点的新连接。== 此行为的具体细节是特定于实现的,不在本规范的范围内。

7.8.2 XRCE Root

XRCE Root 对象代表Agent。 XRCE Agent是所有代理都应实例化的单例对象。

XRCE Root 负责验证客户端应用程序并创建与每个客户端关联的 XRCE ProxyClient 对象。

XRCE Root 上的逻辑操作如表所示。

操作 参数 调用
create_client ResultStatus
object_representation CLIENT_Representation
out:agent_info AGETN_Representation
get_info ResultStatus
info_mask InfoMask
client_info ObjectInfo
out:agent_info ObjectInfo
delete_client ResultStatus
7.8.2.1 create_client

输入

  • client_representation(CLIENT_Representation) : Client的代表

输出

  • returnValue(ResultStatus): 表示操作是否成功以及XRCE ProxyClient对象的当前状态。
  • agent_info(AGENT_Representation):Agent的代表

client_representation 应包含用于初始化 XRCE ProxyClient 的 CLIENT_Representation。 该类型在附件 A,IDL 类型中定义为:

1
2
3
4
5
6
7
8
9
10
@extensibility(FINAL)
struct CLIENT_Representation {
XrceCookie xrce_cookie; // XRCE_COOKIE
XrceVersion xrce_version;
XrceVendorId xrce_vendor_id;
Time_t client_timestamp;
ClientKey client_key;
SessionId session_id;
@optional PropertySeq properties;
};

agent_representation 应包含一个 AGENT_Representation,它通知客户端有关代理的配置。 该类型在附件 A,IDL 类型中定义为:

1
2
3
4
5
6
7
8
@extensibility(FINAL)
struct AGENT_Representation {
XrceCookie xrce_cookie; // XRCE_COOKIE
XrceVersion xrce_version;
XrceVendorId xrce_vendor_id;
Time_t agent_timestamp;
@optional PropertySeq properties;
};

XRCE Agent应根据在 client_representation 中找到的信息执行以下检查和操作:

  • 检查xrce_cookie 以确保它匹配预定义的XRCE_COOKIE 常量。如果它不匹配,则创建将失败并将返回值 StatusValue 设置为 STATUS_ERR_INVALID_DATA。
  • 检查主要版本 (xrce_version[0]) 是否与 XRCE_VERSION_MAJOR 匹配。如果不匹配,则创建将失败并将返回值 StatusValue 设置为 STATUS_ERR_INCOMPATIBLE。
  • 检查由client_key 标识的客户端是否有权连接到XRCE Agent。如果此检查失败,操作将失败并将 returnValue StatusValue 设置为 STATUS_ERR_DENIED。
  • 检查Client属性(如果存在)。这些可能包含特定于供应商的信息,这些信息可能会阻止代理接受来自Client的连接。属性字段可能包括额外的身份验证令牌(例如用户名和密码)或其他配置信息。如果此检查失败,操作将失败并将 returnValue StatusValue 设置为适当的值。
  • 检查是否存在与相同 client_key 关联的现有 XRCE ProxyClient 对象,如果是,则将现有 ProxyClient 的 session_id 与 client_representation 中的进行比较:
    • 如果 ProxyClient 存在且具有相同的 session_id,则操作不应执行任何操作,并将返回值 StatusValue 设置为 STATUS_OK。
    • 如果 ProxyClient 存在且具有不同的 session_id,则操作应删除现有的 XRCE ProxyClient 对象,随后采取与没有与 client_key 关联的 ProxyClient 相同的操作。
  • 检查是否有足够的内部资源来完成创建操作。 如果没有,则操作将失败并将返回值 StatusValue 设置为 STATUS_ERR_RESOURCES。

XRCE Client和 XRCE Agent之间的通信状态由关联的 ProxyClient 管理。 因此,删除现有的 ProxyClient 会重置Client和Agent之间的任何先前通信状态。 任何缓存未决确认的消息都将被丢弃。

如果Agent创建了一个ProxyClient,它应该:

  • 初始化它的状态来拥有特定的 session_id
  • 使用序号0初始化内置流
  • 设置 returnValue StatusValue为 STATUS_OK
  • 使用agent_info返回XRCE Agent的表示

Agent和Client可以使用 client_timestampagent_timestamp来检测 XRCE Client和 XRCE Agent之间的时间同步差异。此信息的使用不在本规范的范围内。

Agent和Client可以使用 XrceVersion 和 XrceVendorId 来进一步配置他们的协议

7.8.2.2 get_info

输入:

  • info_mask(InfoMask):选择需要返回的信息类别
  • client_info(ObjectInfo):Client的代表

输出

  • returnValue(ResultStatus):表示操作是否成功,以及XRCE ProxyClient的当前状态
  • agent_info(ObjectInfo):Agent的代表

其中 client_infoagent_info使用的类型 ObjectInfo定义如下所示:

1
2
3
4
5
@extensibility(FINAL)
struct ObjectInfo {
@optional ActivityInfoVariant activity;
@optional ObjectVariant config;
};

操作 get_info 返回有关 XRCE Agent的信息,并且可以在与 XRCE Agent建立Session之前使用,即在 XRCE Root上调用操作 create_client 之前。

操作 get_info 可用于不同的传输或连接,允许Client搜索和发现 XRCE Agent对象的存在,并选择一个(或多个)具有合适配置和可用性的对象。

client_info 中的 ObjectVariant 成员应包含 CLIENT_Representation,它提供有关发出请求的 XRCE Client的信息。

CLIENT_Representation 的client_key 字段应设置为值CLIENTKEY_INVALID(见附件A,IDL 类型),以免不必要地公开ClientKey。

agent_info 中的 ObjectVariant 成员应包含 AGENT_ActivityInfo,其中包含有关 XRCE Agent的活动信息。

agent_info 中的 ActivityInfoVariant 成员应包含 AGENT_Representation,其中包含有关 XRCE Agent的信息。

ActivityInfoVariant 成员 address_seq 将用于通知 XRCE Client可以到达的传输地址并可以接收对 create_client 的调用。

在 CLIENT_Representation 和 AGENT_Representation 中都可用的 PropertySeq 类型的属性字段可用于实现 XRCE Agent的身份验证协议。 具体机制超出了本规范的范围。

7.8.2.3 delete_client

输出

  • returnValue(ResultStatus): 表示操作是否成功以及对象的当前状态

XRCE Agent会检查ClientKey来定位是否存在XRCE::ProxyClient。 如果对象并没有找到,操作就会失败,并且 returnValue状态值会被设置为STATUS_ERR_UNKNOWN_REFERENCE。如果找到了对象,对象会被删除,returnValue的状态值会被设置为STATUS_OK。

7.8.5 XRCE DataReader

操作如下表定义

操作 参数 调用
read ResultStatus
out:read_data DataRepresentation
object_id ObjectId
read_specification ReadSpecification

7.8.5.1 read

输入:

  • object_id(ObjectId):读取数据的来源对象
  • read_specification(ReadSpecification): 对返回数据进行的约束,只有匹配了约束的数据才会被操作返回。

输出:

  • returnValue(ResultStatus):表示操作是否成功
  • read_data(DataRepresentation): 数据满足了 read_spec,或者存在错误

此操作从 object_id 标识的 XRCE DataReader 中读取一个或多个样本。如果成功读取数据,则应返回 STATUS_OK。

  • 如果对象不存在,则返回 STATUS_ERR_UNKNOWN_REFERENCE
  • 如果客户端因为权限约束不被允许使用引用的 object_id来读取数据,则返回STATUS_ERR_DENIED。

read_spec变量控制着由这个操作返回的数据。它的结构如下表所述

字段 类型 解释
preferred_stream_id octet(8位字节) 指定Agent 将样本发送到Client使用的StreamId。
特殊值 STREAMID_NONE 表示 Agent 可以不受约束地选择 StreamId。
如果代理确定使用 preferred_stream_id 会导致其资源管理出现问题,则允许代理使用与 preferred_stream_id 不同的 StreamId。
data_format DataFormat 选择一种数据格式
content_filter_expression string 选择要读取的数据的内容过滤器表达式。
max_samples (DataDeliveryControl) unsigned short 作为读取结果返回的最大样本数。
特殊值 MAX_SAMPLES_ZERO =0 用于取消任何可能仍处于活动状态的先前读取操作。
特殊值 MAX_SAMPLES_UNLIMITED =0xffff 用于表示对返回的样本数量有限制。
max_elapsed_time (DataDeliveryControl) unsigned short 从读取操作中传送样本可能花费的最长时间(以秒为单位)。
单位是从发出呼叫时间算起的秒数。
特殊值 MAX_ELAPSED_TIME_UNLIMITED = 0 表示没有最大值,操作将继续,直到满足某些其他条件或操作被明确取消。
max_bytes_per_sec (DataDeliveryControl) unsigned short 数据可以返回到读取操作的最大速率(以每秒字节数为单位)。
min_pace_period (DataDeliveryControl) unsigned short 从读取操作返回的数据消息之间的最小间隔(以毫秒为单位)。

data_format 的设置控制读取操作是返回每个消息的单个样本还是样本集合。它还确定数据是否包含出现在 SampleInfo 中的附加信息(参见附录 A IDL 类型)。附加信息包含序列号和时间戳。

content_filter_expression 的设置配置应用于 DataReader 缓存中的样本的内容过滤器。只有过滤器评估为 TRUE 的样本才应返回给 XRCE Client。

max_samples 的设置将读取操作配置为在返回指定数量的样本后终止。值 MAX_SAMPLES_ZERO 可用于取消当前活动的读取操作,而无需发送更多样本。值 MAX_SAMPLES_UNLIMITED 表示对返回的样本数量没有限制。

max_elapsed_time 的设置将读取操作配置为在从进行读取操作的那一刻起经过指定的时间后终止。值 MAX_ELAPSED_TIME_UNLIMITED 表示没有基于经过时间的终止条件。

max_bytes_per_sec 的设置配置可以返回样本的每秒字节数的最大速率。

min_pace_period 的设置配置了从代理发送到客户端的示例消息之间的最小间隔(以毫秒为单位)。这段时间使客户端可以在消息之间进入睡眠周期。

8 XRCE Protocol

8.1 General

DDS-XRCE消息协议专门设计用于解决许多类型低功耗设备中的有限CPU、电源和网络带宽,并使该设备能够在较大的DDS网络中被发现。
该协议有以下特点:

  • 在带宽限制为40-100Kbps的网络上运行。
  • ==使用拥有睡眠周期的设备。这些设备可能每隔几分钟、几天、几个月甚至几年激活一次。==
  • 简单且独立于编程语言,支持用高度专业化的语言或框架编程的设备。
  • 支持最小发现协议,允许在动态发现代理位置的进行即插即用部署
  • 支持访问DDS的全部功能。任何数据类型都可以使用任何DDS QoS进行发布或订阅
  • 支持在同一个或多个DDS主题上高效地多次发送数据更新
  • ==支持以可靠和尽力而为的方式接收信息,即使信息是在客户端处于睡眠周期时发送的==
  • 支持传输级别的安全通信。
  • ==提供对DDS全局数据空间中任何数据的完全读/写访问(受访问控制模块限制)。==
  • 提供需要少于100KB代码的完整实现。

8.2 定义

DDS-XRCE协议定义并使用了client、agent、session、stream和message这些术语。在上层来说,一个client使用DDS-XRCE协议和一个agent交流,是在一个session上的一个stream上进行交换message。

8.2.1 Message

Message是通过传输发送的信息单元,是在DDS-XRCE传输上发送的结构化字节序列。message具有一个序列号,用于对message进行排序,或标识已被传输丢弃的消息。
底层XRCE传输应将每条Message作为一个单元进行传输。单个XRCE传输“消息”应传输单个XRCEmessage。
假设第一个字节具有16字节对齐,则应对XRCE消息进行编码。 因此,编码独立于它前面的任何传输标题或前缀。

8.2.2 Session

一个Session定义了一个client和一个agent之间通过==一次握手建立==的双向链接。session在使用XRCE agent交换消息时被使用。一个XRCE client如果和多个XRCE agent通信时,应该在多个session上发送消息。
一个session可以包含independent、reliable和best-effort消息流。每个session最多可以有256个stream。XRCE客户端和XRCE代理之间最多可以有一个活动session。新的session创建时会结束之前的session。

8.2.3 Stream

Stream表示Session中独立有序的消息流。消息通过序列号在流中排序。不同流使用的序列号(sequenceNr)彼此独立。数据流可以是reliable也可以是best-effort。每个stream使用一个固定的字节序来对消息/子消息的header和payload进行编码。

8.2.4 Client

XRCE client是发起与XRCE agent建session的实体。XRCE client可以在属于已建立的XRCE session的stream上向agent发送和接收message。

8.2.5 Agent

XRCE agent是侦听和接受请求以建立来自XRCE client的session的实体。XRCE agent可以在属于已建立session的stream上向client发送和接收message。

8.3 Message Structure

8.3.1 General

一个XRCE message是由一个message Header跟着一个或多个Submessage组成的,它会被底层的XRCE传输以一个单元的形式进行传输。image-20211102090619688

8.3.2 Message Header

image-20211102090641372

8.3.2.1 Sessions和sessionId

XRCE Client和XRCE Agent之间的Session的建立,是为了通信建立初始的环境。这主要包括了协议版本的交换、供应商的信息以及正确处理消息的其他信息。

一个Session由一个8位的sessionId来确定,sessionId对于给定XRCE Client的XRCE Agent是唯一的。seesionId同时也用来确定Header中是否包含了一个clientKey。

  • 如果sessionId在0~127(0x00到0x7f)之间(含0和127),那么Header应该包含clientKey并且sessionId的作用域由clientKey确定。

  • 如果sessionId在128~255(0x80到0xff)之间(含128 255),那么Header将不含clientKey,sessionId的作用域由message的源地址确定。如果clientKey没有显示出现在message的header,那么XRCE Agent必须能够从message的源地址定位它

有两个sessionId的值是预定的:

  • 值0(0x00)应用于指示在包含clientKey的Header中缺少session。此值被称为SESSION_ID_NONE_WITH_CLIENT_KEY

  • 值128(0x80)应用于指示在未包含clientKey的Header中缺少session。此值被称为SESSION_ID_NONE_WITHOUT_CLIENT_KEY.

8.3.2.2 Stream和streamId

XRCE Stream表示XRCE Client和XRCE Agent之间的独立信息流。 每个XRCE Message都属于一个stream。 属于同一stream的消息必须按其发送顺序进行传递。 属于不同流的消息没有相对于彼此排序。

Stream由他们所属于的Session所限制.

  • 值为0(0x00)的streamId称为STREAMID_NONE。 此流用于仅包含不属于任何流的子消息的消息。
  • streamId在1(0x01)和127(0x7F)之间的流都应为best-effort流。
  • streamId在128(0x80)和255(0xFF)之间的流都应该是reliable流。

根据上述规则,如果streamId不是STREAMID_NONE,则streamId的前导位可以解释为指示流可靠性的标志。

每当创建会话时,都会创建两个内置流:

  • 由值为1(0x01)的streamId标识的内置best-effort流。 这称为STREAMID_BUILTIN_BEST_EFFORTS。
  • 由值128(0x80)的streamId标识的reliable流。 这称为STREAMID_BUILTIN_RELIABLE。
8.3.2.3 sequenceNr

sequenceNr用于对流中的消息进行排序,并且范围仅限于该流。 属于不同流的消息彼此之间是无序的:

  • 对于具有streamId STREAMID_NONE的stream,sequenceNr不强加任何顺序。 但是它仍然可以用来丢弃重复的消息。
  • 对于streamId与STREAMID_NONE不同的流,sequenceNr施加顺序。 流中的消息不得乱序发送。 另外,重复的消息将被丢弃。

序列号的添加和比较应使用[IETF RFC-1982]定义的序列号算法,并且SERIAL_BITS设置为16。这意味着特定客户端会话流的未解决(未确认)消息的最大数目限制为$2^{15}$,即 是32768。
sequenceNr应使用低字节序格式进行编码。

8.3.2.4 clientKey

clientKey唯一地标识XRCE Client并向XRCE Agent对XRCE Client进行身份验证。

如果sessionId在0到127之间,则clientKey将出现在Header上。

  • 如果存在clientKey,则它应包含与XRCE Client关联的ClientKey。
  • 如果clientKey不存在,则XRCE代理应能够从消息的源地址派生与XRCE Client关联的ClientKey。这意味着已经在XRCE Agent上为该特定源地址预配置了ClientKey,或者已将其作为会话建立的一部分进行了交换。

XRCE传输提供的安全机制可以保护clientKey的任何交换。这些安全机制是特定于传输的,可能涉及将每个设备与代理配对或用于建立安全传输连接的一些初始握手。

8.3.3 Submessage Structure

message Header之后的就是一个或多个submessage。一个Submessage由一个SubmessageHeader和一个payload组成。

image-20211102090704134

在一个message中防止多个Submessage的作用是减少带宽,原因是这样可以让多个资源来被一个message进行操作。

submessage应以相对于消息开头的 4 倍数的偏移量开始。。这意味着可以在子消息的结尾和下一个子消息的开始之间进行额外的填充。

8.3.4 Submessage Header

每一个Submessage从一个SubmessageHeader开始,SubmessageHeader结构如下:

image-20211102090716813

8.3.4.1 submessageId

submessageIde定义了submessage的种类。

8.3.4.2 flags

flags区域包括了Submessage的内容相关的信息。

0位是“Endianness”位,表示用于编码子消息头和有效负载的Endianness。如果Endianness位设置为0,则编码应为大端序,否则为小端序。

所有Submessage的flags都应该有Endianness位。特殊的submessage可能定义其他flag位。

8.3.4.3 submessageLength

submessageLength定义了Submessage的长度(含Submessage的头)。

同时它应该独立于flags的定义,以小端序进行编码。

8.3.4.4 payload

payload包含了特殊于submessage的信息,submessage的格式取决于submessageId定义的submessage类型

8.3.5 Submessage Types

image-20211102090734908

由SubmessageId定义的submessage中,有的是单向的,有的是双向的。

SubmessageId Value direction Purpose
CREATE_CLIENT 0 Client到Agent 初始化Client和Agent之间的连接。在Agent上创建一个ProxyClient。
会让Agent调用Root::create_client操作
CREATE 1 Client到Agent 创建一个XRCE对象
会让Agent调用ProxyClient::create 操作
GET_INFO 2 Client到Agent 请求有关XRCE对象的信息
会让Agent调用ROOT::get_info或ProxyClient::get_info操作
DELETE 3 Client到Agent 删除一个对象或删除一组XRCE对象
会让Agent调用ProxyClient::delete操作或者Root::delete_client操作
STATUS_AGENT 4 Agent到Client 发送一个对CREATE_CLIENT的响应,包含Agent相关的信息
携带Root::create_client操作的返回值
STATUS 5 Agent到Client 通常用来响应CREATE、UPDATE或者DELETE。包含一个XRCE对象的状态信息
携带PoxyClient::create,update或者delete的返回值
INFO 6 Agent到Client 通常发送一个对GET_INFO的响应。包含关于一个XRCE::Object或者一个XRCE Agent的信息
携带Root::get_info或者ProxyClient::get_info的返回值
WRITE_DATA 7 Client到Agent 使用XRCE的DataWriter来写数据
会让Agent来调用ProxyClient::write操作
READ_DATA 8 Client到Agent 使用XRCE的DataReader来读数据
会让Agent来调用ProxyClient::read操作
DATA 9 Agent到Client 响应READ_DATA,提供由XRCE的DataReader接收到的数据
携带ProxyClient::read的返回值
ACKNACK 10 双向 发送肯定或者否定的信号给一些序列号
HEARTBEAT 11 双向 通知可用的序列号的范围
RESET 12 双向 重置session
FRAGMENT 13 双向 传递数据片段。用于发送大小大于底层传输支持的大小的消息

8.4 互操作模型(Interaction Model)

8.4.1 General

本章节主要描述典型的信息流。

XRCE协议的目的就是使实现最小化发现和设置流量的客户端成为可能。因此一些信息流是可选的,而且可以被XRCE的Client和Agent进行带外(out-of-band,OOB)设置。

8.4.2 使用预先配置的DataWriter进行数据发送

下面的消息流说明了XRCE Client使用XRCE Agent写入数据的完整消息集。 XRCE代理已预先配置为创建一个包含DomainParticipant,Publisher和DataWriter的XRCE应用程序。预先配置了object_id的DataWriter为XRCE Client所知。

Message flow to send data using a pre-configured DataWriter.JPG

已为Clinet(由ClientKey标识)预先配置了XRCE Agent,以便它可以识别出现在 CREATE_CLIENT消息中的application_object_id。 CREATE_CLIENT的接收触发相应XRCE对象的 创建或重用这些XRCE对象包括XRCE DataWriter及其相应的DDS DataWriter。 随后的WRITE_DATA消息通过那些DataWriter的ObjectId来使用DDS发布数据。

8.4.3 使用预先配置的DataReader进行数据接收

下面的消息流说明了XRCE Client用来通过XRCE Agent接收数据的完整消息集。 XRCE Agent已预先配置为创建一个包含DomainParticipant,Subscriber和DataReader的XRCE Application。 XRCE Client知道DataReader预先配置的object_id。

Message flow to receive data using a pre-configured DataReader.JPG

已为Client(由 ClientKey标识)预先配置了一个Agent,从而可以使它识别 出现在 CREATE_CLIENT消息中的 application_object_id。CREATE_CLIENT的接收触发相应 XRCE对象的 创建或重用其中包括 XRCE DataReader及其相应的 DDS DataReader。 随后的READ消息引用这些DataReader的 ObjectId以便从DDS域接收数据。

8.4.4 发现一个Agent

下面的消息流说明了XRCE客户端发现XRCE代理所需的消息。 仅当未使用XRCE代理的TransportLocator预先配置客户端时,才需要此流程。 它允许将XRCE客户端配置为满足一个或多个TransportLocator(可能包括多播地址)的需求,以便动态发现代理的存在和实际地址。

作为此过程的结果,XRCE客户端可能发现多个XRCE代理。 在那种情况下,它可能会使用收到的有关XRCE代理配置的信息(例如,字段版本,vendor_id或在AGENT_Representation中找到的属性)和XRCE代理活动(例如,ActivityInfo中的可用性字段)来选择最合适的XRCE代理,甚至连接到多个XRCE代理

Message flow for a Client to an Agent.JPG

XRCE 客户端使用 GET_INFO 查询 XRCE 代理的信息,代理响应后,客户端选择一个代理并使用 CREATE_CLIENT 消息连接到它。 代理以 STATUS_AGENT 响应,指示连接是否成功以及是否代表 XRCE 客户端创建了 ClientProxy。

8.4.5 链接到一个Agent上

下面的消息流说明了XRCE Client连接到XRCE Agent所需的消息。Client连接后,它可以创建资源或调用现有资源上的操作。

Message flow for a Client to connect to an Agent.JPG

XRCE Client使用 CREATE_CLIENT 消息连接到 Agent。 Agent 以 STATUS_AGENT响应,该状态指示连接是否成功以及是否代表 XRCE客户端创建了ClientProxy。

8.4.6 创造一个完整的Application

下面的消息流说明了已经连接的XRCE Client 创建完整的XRCE Application所需的消息。

Message flow for a Client to create an ApplicationJPG.JPG

XRCE Client使用 CREATE 消息创建 XRCE Application。 CREATE消息带有一个CREATE_Payload,其中包含一个ObjectKind设置为OBJK_APPLICATION的 ObjectVariant。 相应的 OBJK_APPLICATION_Representation可以使用 REPRESENTATION_BY_REFERENCE 来引用在代理中预先配置的Application,也可以使用REPRESENTATION_AS_XML_STRING来完整地描述该 Application,包括任何必要的 Type,Qos和DDS实体。

8.4.7 定义Qos配置

下面的消息流说明了已连接的XRCE Client动态定义XRCE QosProfiles所需的消息,这些消息以后可用于创建其他XRCE对象。

Message flow for a Client to define Qos Profiles.JPG

XRCE Client使用 CREATE消息来定义Qos配置文件。 CREATE消息包含一个CREATE_Payload,其中包含一个ObjectKind设置为OBJK_QOSPROFILE的ObjectVariant。 相应的 OBJK_QOSPROFILE_Representation可以使用 REPRESENTATION_AS_XML_STRING来完整描述Qos概要文件。

8.4.8 定义类型

下面的消息流说明了已连接的XRCE Client动态定义XRCE Type所需的消息,这些XRCE Type以后可用于创建XRCE Topic对象。

Message flow for a Client to a Client to define Types.JPG

XRCE Client使用 CREATE消息创建XRCE类型。 CREATE消息带有一个CREATE_Payload,其中包含一个ObjectKind设置为OBJK_TYPE的ObjectVariant。 对应的 OBJK_TYPE_Representation可以使用 REPRESENTATION_AS_XML_STRING 来完整描述 DDS-XTYPES类型,包括任何引用的类型。

8.4.9 创建一个Topic

下面的消息流说明了已连接的XRCE Client动态创建XRCE主题所需的消息,该主题以后可用于创建XRCE DataWriter和DataReader对象。

Message flow for a Client to a Client to define a Topic.JPG

XRCE Client使用 CREATE消息创建 XRCE Topic。 CREATE消息包含一个CREATE_Payload,其中包含一个ObjectKind设置为OBJK_TOPIC的ObjectVariant。 相应的 OBJK_TOPIC_Representation可以使用 REPRESENTATION_IN_BINARY或 REPRESENTATION_AS_XML_STRING来完全定义主题。

8.4.10 创建一个DataWriter

下面的消息流说明了已连接的XRCE Client动态创建XRCE DataWriter所需的消息,该资源具有发布数据所需的所有资源。

XRCE Agent可能具有QoS配置文件的先验知识,从而允许XRCE客户端按名称引用Qos,而无需明确定义它们。 或者,XRCE Client可以将它们的定义包括在XRCE DataWriter资源的定义中。

Message flow for a Client to create a DataWriter.JPG

XRCE Client使用 CREATE消息创建 XRCE DataWriter。 CREATE消息包含一个CREATE_Payload,其中包含一个ObjectKind设置为OBJK_DATAWRITER的ObjectVariat。 相应的 DATAREADER_Representation可以使用 REPRESENTATION_IN_BINARY或 REPRESENTATION_AS_XML_STRING来完全定义DataWriter。 这两种表示方式都可以指定DataWriter Qos。 DATAREADER_Representation也可以使用REPRESENTATION_BY_REFERNCE来引用Agent已知的DataWriter定义。

8.4.11 创建一个DataReader

下面的消息流说明了已连接的XRCE Client动态创建XRCE DataReader所需要的消息,该资源具有订阅数据所需的所有资源(原文为publish data我觉得有点问题)

XRCE Agent可能具有QoS配置文件的先验知识,从而允许XRCE客户端按名称引用这些Qos,而无需明确定义。 或者,XRCE Client可以将它们的定义包括为XRCE DataReader资源的定义中。

Message flow for a Client to create a DataReader.JPG

XRCE Client使用 CREATE消息创建 XRCE DataReader。 CREATE消息包含一个CREATE_Payload,其中包含一个ObjectKind设置为OBJK_DATAREADER的ObjectVariant。 相应的 OBJK_DATAREADER_Representation可以使用 REPRESENTATION_IN_BINARY或 REPRESENTATION_AS_XML_STRING来完全定义DataReader。 这两种表示形式都允许指定DataReader Qos。 OBJK_DATAREADER_Representation也可以使用REPRESENTATION_BY_REFERENCE来引用Agent已知的DataReader定义

8.4.12 从一个资源上获取信息

下面的消息流说明了XRCE Client如何查询有关资源的信息。 XRCE Client可以使用此机制来确定XRCE Agent代表XRCE Client管理的任何DDS代理实体的QoS。 它还可以用于读取XRCE Agent已知的QoS配置文件和类型声明。

Message flow for a Client to update a Resource.JPG

XRCE Client使用GET_INFO消息从由其 ObjectId标识的 XRCE Object获取信息。XRCE Agent以包含ObjectVariant的 INFO消息作为响应。 ObjectVariant的ObjectKind适用于指定的 ObjectId。

8.4.13 更新一个资源

下面的消息流说明了XRCE Client 如何更新XRCE DataReader。 XRCE Client可以使用此机制来更改XRCE Agent代表XRCE Client管理的任何DDS代理实体的QoS参数。

Message flow for a Client to update a Resource.JPG

XRCE Client使用CREATE消息,将属性reuse设置为TRUE,并将属性replace设置为TRUE,以表示它希望更新由ObjectId标识的对象。 CREATE消息包含一个ObjectVariant,其中ObjectKind设置为指定的ObjectId的适当值。 XRCE代理使用ObjectVariant中包含的新配置更新对象,并以STATUS消息作为响应。

8.4.14 可靠通信

可靠性是针对每个Stream分别实现的,并且仅针对由stream_id值介于0x80和0xFF之间标识的可靠流。 (参见第8.3.2.2节Streams和streamId。)

一个Stream恰好有两个端点,即发送端点和接收端点。 请注意,对于某些流,发送者是XRCE Client,例如 当XRCE Client使用流将数据写入XRCE Agent时。 同样,在其他流中,发送方可以是XRCE Agent,例如,当XRCE Agent 使用流来发送XRCE Client在READ操作中请求的数据时。

Stream上的发送者和接收者端点各自执行其自己的协议状态机。 这些在以下小节中进行了说明。
序列号添加和比较应使用第8.3.2.3节sequenceNr中规定的序列号算法。

8.4.14.1 可靠发送状态机

由端点在流上发送的协议如下图所示。

流上可靠协议的发送状态机.JPG

发送方维护与流关联的两个状态变量。 最高发送序列号(HighestSentSequenecNumber)和最高确认序列号(HighestAcknowledgedSequenceNumber)。

每次发送消息时,HighestSentSequenecNumber都会增加。 ACKNACK消息的接收会 更新HighestAcknowledgedSequenceNumber。
当HighestAcknowledgedSequenceNumber小于HighestSentSequenceNumber时,发送方将HeartBeat消息发送给接收方,该消息宣告HighestSentSequenecNumber。 这些HeartBeat消息可以是定期的,也可以使用特定于供应商的机制进行优化。 要求以一定的速率发送它们,直到HighestAcknowledgedSequenceNumber与HighestSentSequenceNumber匹配为止。

8.4.14.2 可靠接收状态机

由端点在流上接收的协议如下图所示:

流上可靠协议的接收状态机.JPG

接收方包括两个和流关联的状态变量。最高接受序列号(HighestReceivedSequenceNumber)和最高确认序列号(HighestAnnouncedSequenceNumber )。

每次接收到一条消息时,HighestReceivedSequenceNumber可能会更新(假定已接收到所有先前的消息)。 HighestAnnouncedSequenceNumber也会进行调整。

每次收到HEARTBEAT时,可能会调整HighestAnnouncedSequenceNumber。

如果接收方是XRCE Client,则当HighestReceivedSequenceNumber小于HighestAnnouncedSequenceNumber时,接收方将发送ACKNACK消息以请求与丢失的序列号相对应的消息。 这些ACKNACK消息可以是周期性的,或者可以使用特定于供应商的机制进行优化。

如果接收方是XRCE Agent,则它仅响应于接收到HEARTBEAT才发送ACKNACK消息。

这样做是为了避免使XRCE Client不堪重负或在不适当的时间唤醒它。

8.5 XRCE 对象操作的可追溯性

本节总结了用于在 XRCE 对象模型上实现每个操作的消息,确保已涵盖所有操作。

使用的消息触发每个操作并接收结果汇总在表 14 中

XRCE对象类型 操作 用于调用的消息 用于返回的消息
XRCE Root create_client CREATE_CLIENT STATUS_AGENT
XRCE Root get_info GET_INFO INFO
XRCE Root delete_client DELETE STATUS_AGENT
XRCE ProxyClient create CREATE(标志为创建) STATUS
XRCE ProxyClient update CREATE(标志为重用) STATUS
XRCE ProxyClient get_info GET_INFO INFO
XRCE ProxyClient delete DELETE STATUS
XRCE DataWriter write WRITE_DATA, FRAGMENT STATUS
XRCE DataReader read READ_DATA DATA, FRAGMENT, STATUS

9 XRCE Agent 配置

9.1 常规

XRCE Agent可以被配置为使得它具有先验知识 XRCE 对象。 这允许 XRCE Client使用表示格式 REPRESENTATION_BY_REFERENCE 来以非常紧凑的方式引用和创建 XRCE 对象,请参阅第 7.7.3.3.1 节 REPRESENTATION_BY_REFERENCE 格式。

本规范提供了两种标准机制来配置 XRCE Agent。 实现还可以提供额外的机制:

  • 使用 XRCE 协议进行远程配置
  • 基于文件的本地配置

这些机制在以下条款中进行了描述。

9.2 使用XRCE协议进行远程配置

应用程序可以使用 XRCE Client,其唯一目的是定义和创建用于其他应用程序的 XRCE 对象。 这种类型的应用程序称为 XRCE ConfigurationClient。

XRCE ConfigurationClient 使用的协议与任何其他 XRCE Client 使用的协议相同。 唯一的区别是 XRCE ConfigurationClient 从不使用 READ_DATA 或 WRITE 消息。 它仅使用创建、更新或检索有关 XRCE 对象的信息的消息。

任何其他 XRCE Client都可以引用由XRCE ConfigurationClient创建的 XRCE 对象。

远程配置机制的典型用途是可用于在部署之前配置代理或交互式配置系统的工具。

请注意, XRCE ConfigurationClient可能使用不同的网络或传输与代理进行通信,这可能与典型的 XRCE Client具有不同的约束。

image-20211102101157490

9.3 基于文件的配置

10 XRCE部署

DDS-XRCE PIM 中描述的所有操作都与客户端应用程序与单个 DDS XRCE Agent的交互有关。 因此,所有操作的范围仅限于与该 DDS-XRCE Agent的交互。 然而,尽管连接到不同的 DDS-XRCE Agent,客户端应用程序仍可能相互交互。 这些交互将作为 DDS-XRCE Agent在 DDS 域参与者实体上创建和执行操作的结果而发生,这些实体根据 DDS 规范交换信息。

10.1 XRCE Client到DDS的通信

该规范定义了 XRCE Client用于与代理 DDS 域中客户端的 XRCE Agent通信的协议。 这样做的主要结果是 XRCE Client现在可以与任何 DDS 域参与者进行通信。

DDS 域参与者将发现 XRCE Agent代表Client创建的代理 DDS 实体,并使用标准的 DDS-RTPS 互操作性协议与代理进行通信。

XRCE Client将使用 XRCE 协议与 XRCE Agent通信。 使用该协议,它可以指导 XRCE Agent创建新的 DDS 实体,并使用这些实体在DDS全局数据空间上读写数据。

这种类型的部署如下面的图所示。

image-20211102102011872

XRCE Client使用 XRCE 协议与 XRCE Agent通信。 XRCE Agent使用 DDS-RTPS 协议与 DDS 域中的其他 DDS 域参与者通信。

10.2 XRCE Client 通过DDS到XRCE Client的通信

XRCE Agent在 DDS 域中显示为 DDS 域参与者。 因此,连接到不同 XRCE Agent的 XRCE Client应用程序无需进一步配置即可相互通信。

每个 XRCE Agent将其他 XRCE Agent视为 DDS 域参与者,与任何其他 DDS 域参与者没有区别,并使用 DDS-RTPS 与他们通信。 XRCE Agent将将该通信中继到其各自的 XRCE Client。

这种类型的场景如下图 所示

image-20211102102242827

XRCE Client使用 XRCE 协议与其各自的 XRCE Agent进行通信。 这些 XRCE Agent使用 DDS-RTPS 相互通信,因为每个代理都是 DDS 域上的 DDS 域参与者。

10.3 由XRCE Agent当中间人的Client到Client通信

多个 XRCE Client应用程序可以连接到同一个 XRCE Agent。

它取决于 XRCE Agent的实现,无论它创建的 DDS 实体是每个 XRCE Client专有的,还是在 XRCE Client之间共享的。但是,XRCE Client可观察到的行为应如同 DDS XRCE Agent创建每个 XRCE Client专有的单独 DDS 对象。

如果 XRCE Agent代表每个 XRCE Client创建单独的 DDS 实体,那么每个实体都将拥有自己的代理 DDS 域参与者。这两个 DDS 域参与者将在 DDS 域上相互通信。在这种情况下,两个 XRCE Client将在 XRCE Agent的“代理”下相互通信,而无需在 XRCE Agent中进行额外的配置或逻辑。

如果 XRCE Agent在不同的 XRCE Client之间共享 DDS 实体,那么行为“好像”每个都有自己独立的实体的要求需要本地 DDS DataWriter 实体发现并匹配同一 DomainParticipant 中的本地 DDS DataReader 实体。这将自动导致 XRCE Client使用代理作为“代理”相互通信,而无需进一步配置。

XRCE Agent的实现可以选择在本地 XRCE DataWriter 和 DataReader 对象之间创建更快的通信路径,以便来自 XRCE DataWriter 的数据可以直接进入匹配的 XRCE DataReader,而无需通过关联的 DDS 实体。这个“捷径”可以作为一种优化来实施,因为它不会影响任何协议,也不会影响与其他 XRCE Client、Agent或 DDS 域参与者的互操作性。

这种类型的场景如下图 所示。

image-20211102103306558

多个 XRCE Client可以连接到同一个 XRCE Agent。 XRCE Client使用 XRCE Agent作为“代理”相互通信。 这种“客户端到客户端”的通信可以利用相关的 DDS 对象,或者可以使用代理内部的优化路径,从而缩短 DDS 对象的使用。

10.4 联合部署

10.5 Client应用之间直接P2P通信

10.6 组合部署

11 传输映射

11.1 传输模型

XRCE 协议不限于任何特定的传输。它可以映射到大多数现有的网络传输,如 UDP、TCP 和低带宽传输,如蓝牙、ZigBee 和 6LoWPAN。

为了在没有额外开销的情况下运行,预计传输支持以下功能:

  1. 传送至少 64 字节的消息。
  2. 处理消息的完整性,丢弃任何损坏的消息。此功能不限制可用的传输;它只需要在来自不处理本机完整性的传输的消息中附加一个 CRC。
  3. 提供接收消息的大小以及源地址。此要求不限制可用的传输;它只需要在来自传输本身不包含信息的消息中添加源信息和大小。
  4. 支持双向通信。
  5. 提供传输级安全,特别是客户端验证代理的方法和安全(加密和验证)消息交换的方法。或者,XRCE Agent和Client可以部署在安全网络层(例如加密 VPN)之上。

传输明确不需要以下功能:

  1. 不需要提供可靠性。消息可能会被丢弃。
  2. 不需要提供顺序。消息可能会乱序到达。
  3. 不需要提供丢弃消息的通知。

不满足上述某些先决条件的传输仍可通过添加丢失的信息作为 XRCE message的信封来使用。这将作为映射到该特定协议的一部分来完成。

例如,如果缺少源地址或消息大小,它们可以作为前缀添加到 XRCE 消息。如果传输不支持完整性,可以将 CRC 后缀添加到 XRCE 消息。

11.2 UDP 传输

UDP 传输满足第 11.1 节中列出的所有功能。 除了它不提供安全性。

对于需要安全性的应用程序,有“数据报传输层安全性”(DTLS) 标准 [DTLS],它在 UDP/IP 之上提供安全性。 或者,UDP 可以部署在专用网络 (VPN) 上,它在 UDP 之下的 IP 层提供安全性。

由于 XRCE 协议不需要传输提供可靠性、排序或故障通知,因此它可以简单地映射到“数据报”传输,例如 UDP/IP。

11.2.1 传输定位器

当 XRCE 映射到 UDP v4 时,union类型的TransportLocator 应使用 TransportLocatorFormat 鉴别器为 ADDRESS_FORMAT_MEDIUM。 这将选择类型的 medium_locator成员。

1
2
3
4
struct TransportLocatorMedium {
octet address[4];
unsigned short port;
};

当 XRCE 映射到 UDP v6 时,union类型的TransportLocator 应使用 TransportLocatorFormat 鉴别器为 ADDRESS_FORMAT_LARGE。 这将选择类型的 large_locator成员。

1
2
3
4
struct TransportLocatorLarge {
octet address[16];
unsigned long port;
};

11.2.4 Agent发现

XRCE Agent发现可以使用 UDP/IP 多播完成。 XRCE Agent应预先配置它们应侦听的多播地址和端口号。默认情况下,它们应为地址 239.255.0.2 和端口 7400。

为了通过多播发现代理,XRCE Client应定期向配置的多播地址和端口发送 GET_INFO 消息(见 8.3.5.3)。该消息应调用 XRCE Agent上的 get_info 操作(见 7.8.2.2),该操作应响应并包括其 TransportLocators。一旦 XRCE Client收到来自代理的合适响应,它应停止发送定期消息。

XRCE Agent发现可以使用 UDP/IP 单播完成。 XRCE Client应预先配置有 XRCE Agent可能位于的候选 UDP 地址和端口列表。

为了通过单播发现代理,XRCE Client应定期向配置的地址和端口发送 GET_INFO 消息(见 8.3.5.3)。该消息应调用 XRCE Agent上的 get_info 操作(见 7.8.2.2),该操作应响应并包括其 TransportLocators。一旦 XRCE Client收到来自代理的合适响应,它应停止发送定期消息

11.3 TCP 传输

11.3.4 Agent发现

即使通信将通过 TCP,XRCE Agent发现可以使用 UDP/IP 多播完成。

XRCE Agent可以预先配置多播地址和端口号,它们将对多播进行侦听。默认情况下,它们应为地址 239.255.0.2 和端口 7400。

为了通过多播发现代理,XRCE Client应定期向配置的多播地址和端口发送 GET_INFO 消息(见 8.3.5.3)。该消息应调用 XRCE Agent上的 get_info 操作(见 7.8.2.2),该操作应响应并包括其 TransportLocators。一旦 XRCE Client收到来自代理的合适响应,它应停止发送定期消息。

XRCE Agent发现可以使用 TCP/IP 完成。 XRCE Client应预先配置有 XRCE Agent可能位于的候选 TCP 地址和端口列表。

为了通过单播发现代理,XRCE Client应定期尝试与配置的地址和端口建立 TCP 连接。建立连接后,它将发送 CREATE_CLIENT 消息(见 8.3.5.1)。该消息应调用 XRCE Agent上的 create_client 操作(见 7.8.2.1),该操作要么接受要么产生错误。一旦 XRCE Client收到来自代理的合适响应,它应停止进行定期连接尝试。

文章目录

  1. DDS-XRCE
    1. 1 scope
    2. 4 术语和定义
    3. 5 符号解释
    4. 7 XRCE Object Model
      1. 7.1 General
      2. 7.2 XRCE Client
      3. 7.3 XRCE Agent
      4. 7.4 Model Overview
        1. Root
        2. ProxyClient
        3. Application
        4. AccessController
        5. DomainParticipant
      5. 7.5 XRCE DDS Proxy Objects
      6. 7.6 XRCE Object Identification
      7. 7.7 对XRCE Object上的操作进行建模所用到的数据类型
        1. 7.7.1 Data and Samples
        2. 7.7.2 DataRepresentation
        3. 7.7.4 ObjectId
        4. 7.7.5 ObjectKind
        5. 7.7.6 ObjectIdPrefix
        6. 7.7.7 ResultStaus
        7. 7.7.8 BaseObjectRequest
        8. 7.7.9 BaseObjectReply
      8. 7.8 XRCE 对象操作
        1. 7.8.1 ClientKey 的使用
        2. 7.8.2 XRCE Root
          1. 7.8.2.1 create_client
          2. 7.8.2.2 get_info
          3. 7.8.2.3 delete_client
        3. 7.8.5 XRCE DataReader
        4. 7.8.5.1 read
    5. 8 XRCE Protocol
      1. 8.1 General
      2. 8.2 定义
        1. 8.2.1 Message
        2. 8.2.2 Session
        3. 8.2.3 Stream
        4. 8.2.4 Client
        5. 8.2.5 Agent
      3. 8.3 Message Structure
        1. 8.3.1 General
        2. 8.3.2 Message Header
          1. 8.3.2.1 Sessions和sessionId
          2. 8.3.2.2 Stream和streamId
          3. 8.3.2.3 sequenceNr
          4. 8.3.2.4 clientKey
        3. 8.3.3 Submessage Structure
        4. 8.3.4 Submessage Header
          1. 8.3.4.1 submessageId
          2. 8.3.4.2 flags
          3. 8.3.4.3 submessageLength
          4. 8.3.4.4 payload
        5. 8.3.5 Submessage Types
      4. 8.4 互操作模型(Interaction Model)
        1. 8.4.1 General
        2. 8.4.2 使用预先配置的DataWriter进行数据发送
        3. 8.4.3 使用预先配置的DataReader进行数据接收
        4. 8.4.4 发现一个Agent
        5. 8.4.5 链接到一个Agent上
        6. 8.4.6 创造一个完整的Application
        7. 8.4.7 定义Qos配置
        8. 8.4.8 定义类型
        9. 8.4.9 创建一个Topic
        10. 8.4.10 创建一个DataWriter
        11. 8.4.11 创建一个DataReader
        12. 8.4.12 从一个资源上获取信息
        13. 8.4.13 更新一个资源
        14. 8.4.14 可靠通信
          1. 8.4.14.1 可靠发送状态机
          2. 8.4.14.2 可靠接收状态机
      5. 8.5 XRCE 对象操作的可追溯性
    6. 9 XRCE Agent 配置
      1. 9.1 常规
      2. 9.2 使用XRCE协议进行远程配置
      3. 9.3 基于文件的配置
    7. 10 XRCE部署
      1. 10.1 XRCE Client到DDS的通信
      2. 10.2 XRCE Client 通过DDS到XRCE Client的通信
      3. 10.3 由XRCE Agent当中间人的Client到Client通信
      4. 10.4 联合部署
      5. 10.5 Client应用之间直接P2P通信
      6. 10.6 组合部署
    8. 11 传输映射
      1. 11.1 传输模型
      2. 11.2 UDP 传输
        1. 11.2.1 传输定位器
        2. 11.2.4 Agent发现
      3. 11.3 TCP 传输
        1. 11.3.4 Agent发现