63次发布

0.10.3 2024年8月2日
0.10.2 2024年7月31日
0.10.1 2024年4月19日
0.9.1 2024年3月27日
0.0.3 2020年11月25日

139网络编程

Download history 252/week @ 2024-05-03 204/week @ 2024-05-10 212/week @ 2024-05-17 231/week @ 2024-05-24 201/week @ 2024-05-31 389/week @ 2024-06-07 327/week @ 2024-06-14 399/week @ 2024-06-21 463/week @ 2024-06-28 752/week @ 2024-07-05 456/week @ 2024-07-12 543/week @ 2024-07-19 770/week @ 2024-07-26 813/week @ 2024-08-02 650/week @ 2024-08-09 685/week @ 2024-08-16

2,927 每月下载量
用于 3 个包

Apache-2.0

2MB
40K SLoC

RustDDS

continuous-integration codecov

RustDDS数据分发服务 的纯Rust实现。最新版本可在 crates.io 上找到,API文档在 docs.rs 上。GitHub仓库 RustDDS 跟踪开发。

RustDDS 由 Atostek Oy 开发。Atostek 提供与DDS、ROS2和机器人软件相关的支持和软件开发服务。作为我们工作的一部分,我们开源了RustDDS实现。

我们试图将DDS应用程序接口的关键思想翻译成Rust概念,同时也遵循Rust约定。因此,API并不是严格按照DDS规范编写的,而是使用Rust概念和约定实现的函数等效近似。

数据分发服务

数据分发服务(DDS)是面向实时系统的数据分发服务,是一个面向机器到机器连接性的对象管理组(OMG)框架,旨在通过发布-订阅模式实现可扩展、实时、可靠、高性能和互操作的数据交换。DDS满足了空中交通管制、智能电网管理、自动驾驶汽车、机器人、交通系统、发电、医疗设备、仿真和测试、航空航天和国防等需要实时数据交换的应用的需求 [Wiki]

当前实现状态

目前,实现已足够完整,可以与ROS2软件进行数据交换。

建议使用ros2-client与ROS组件通信。RustDDS中的ros2模块不再使用。

版本 0.10.0

扩展了用于将序列化格式附加到RTPS的DeserializerAdpter接口,以支持使用"种子"值进行反序列化。这允许反序列化过程输入除输入字节流之外的其他运行时数据。

0.10.1

  • 使RTPS时间戳的本地滴答计数公开访问

0.10.2

  • 错误修复:如果数据样本到达顺序错误,可靠的DataReader交付的数据样本顺序错误。
  • 更改Windows上的套接字初始化行为。
  • CDR序列化现在是一个独立的Rust crate。

0.10.3

  • 修复了提高与CycloneDDS互操作性的错误。
  • 两个示例程序用于测试CycloneDDS示例

版本 0.9.2

  • 重新设计内部缓存以解决连接中的问题。

版本 0.9.1

  • 修复了许多错误。
    • DDSCache中存在内存泄漏。
    • 可靠的接收器可能会卡住。
  • 与FastDDS的DDS安全性互操作性得到改善。
  • 新增安全功能,例如PKCS#11支持、RSA身份验证支持

版本 0.9

  • 新版本发布,以启用ros2-client中的新功能
  • DDS安全性正在进行的互操作性测试。
  • 支持域参与者状态事件,主要与发现相关。
  • 小的API更改
    • 简化命名
    • QoS对象现在是可序列化的
  • 与可靠连接的协议错误修复。

版本 0.8.6

  • 功能security即将完成。RustDDS可以安全地与自己通信,但与其他DDS实现进行的互操作性测试仍在进行中。
  • 修复了处理序列号时的一些错误。
  • RTPS Writer数据发送重写。
  • 修复错误:重传数据上缺少源时间戳。

版本 0.8.5

  • 功能security已合并到master,但它仍然是一个工作正在进行中的项目,因此尚未启用。
  • 应该再次在Windows上工作
  • 反序列化中更宽松的生命周期限制
  • 简化Key特质的用法

版本 0.8

新功能

  • 异步API可用。
  • 使用mio-0.6或mio-0.8进行轮询。
  • 简化了DataReader SimpleDataReader。它只支持.take()调用,但应该比常规DataReader更轻更快。它旨在只提供足够的函数来实现ROS2订阅者。

此版本破坏了兼容性

  • read() / .take()调用返回的数据的命名已从Result更改为Sample。这样做是为了减少混淆的命名,因为在以前的用法中,Err变体中的Result并不表示实际的错误条件,而是一个数据实例丢弃操作。
  • 错误类型已重新设计,以更好地反映可能导致的错误,而不是为整个API有一个复杂的错误类型。这是与DDS规范有意的偏差,以使实现更类似于Rust。

版本 0.6

此版本与0.5.x不兼容。公共API名称有一些细微差异。进行了更改,以遵循Rust命名约定。版本0.6.0修复了回归,其中与eProsima FastRTPS的通信只能持续一段时间。

版本 0.5

此版本与0.4.0不兼容。差异包括

  • 命名规范更接近Rust风格,而不是DDS规范——主要是大写和下划线。
  • 一些新函数现在需要拥有自己的String而不是&str。只需添加.to_string()即可修复。
  • 键大小检测(是否超过16字节?)现在通过派生宏实现了一个特质。

特性状态

  • 发现 ✅
  • 可靠性QoS:可靠和尽力而为 ✅
  • 历史QoS ✅
  • RTPS over UDP ✅
  • 广播UDP ✅
  • 非阻塞I/O ✅
  • 主题种类:有键和无键 ✅
  • 零拷贝接收路径 ✅
  • 零拷贝传输路径
  • 主题创建 ✅
  • 主题查找 ✅
  • 分区QoS
  • 基于时间的过滤器QoS
  • 所有权QoS
  • 表示QoS:一致/原子样本集和排序
  • 截止时间和延迟预算QoS
  • 样本碎片化(大对象交换) ✅
  • wait_for_acknowledgments
  • 域参与者监听器(或等效) ✅
  • 主题监听器(或等效)
  • 使用Rust async任务的其他API ✅
  • 本地连接的共享内存传输

互操作性

使用可用的"形状"演示程序。数据交换在两个方向上都工作

  • RTI Connext
  • eProsima FastRTPS
  • OpenDDS
  • Twin Oaks Computing

使用

请参阅包内包含的示例,以及互操作性测试

数据序列化和密钥

一些现有的DDS实现使用代码生成来为每种有效负载类型实现DataReader和DataWriter类。

我们不依赖于代码生成,而是使用Rust泛型编程:有一个泛型DataReader和DataWriter,由有效负载类型D和序列化适配器类型SA参数化。使用Serde库进行有效负载数据的序列化和反序列化。

当与DataWriter一起使用时,有效负载类型D必须实现serde::Serialize,当与DataReader一起使用时,必须实现serde::DeserializeOwned。许多现有的Rust类型和库已经支持Serde,因此它们无需修改即可使用。

在DDS中,包含多个不同实例的WITH_KEY主题,这些实例通过键来区分。密钥必须以某种方式嵌入到数据样本中。在我们的实现中,如果有效负载类型D在WITH_KEY主题中通信,则D还必须实现特质Keyed

特质Keyed需要一个方法:key(&self) -> Self::K,它用于从D中提取相关类型K的键。键类型K必须实现特质Key,这是现有特质Eq + PartialEq + PartialOrd + Ord + Hash + Clone + Serialize + DeserializeOwned的组合,并且没有其他方法。

为OMG通用数据表示(CDR)提供了序列化适配器类型SA(Serde数据格式的包装),因为这是DDS/RTPS使用的默认序列化格式。可以通过提供Serde 数据格式实现来使用其他序列化格式进行DDS通信的对象。

对DDS规范的有意偏离

原因

DDS 1.4规范指定了一个对象模型和一组API,这些API构成了DDS规范。这些API的设计,例如命名约定和内存管理语义,在Rust世界中并不完全适用。我们试图创建一个设计,在其中,重要的DDS思想得以保留和实现,但以适合Rust的方式。这些设计妥协只能在DDS面向应用的API中体现。网络侧仍在努力与现有的DDS实现完全互操作。

类层次结构

DDS指定了一个类层次结构,它是API的一部分。这个层次结构不一定被遵循,因为Rust在继承和派生类方面并不像C++那样使用。

命名约定

我们试图遵循Rust的命名约定。

数据监听器和WaitSets

DDS提供了两种等待到达数据的替代方法,即WaitSets和Listeners。我们选择使用来自mio crate的非阻塞IO API来替代这些方法。DDS DataReader对象可以直接与mio的Poll接口一起使用。应该可以实现其他API,例如在该API之上实现异步API。

实例句柄

DDS使用“实例句柄”,它们类似于指向由DDS实现管理的对象的指针。这似乎与Rust内存处理不太相容,所以我们选择不实现这些。

实例句柄可以用来引用具有特定键的数据值(样本)。我们已经编写了API来直接使用键,因为这看起来在语义上是等效的。

返回代码

DDS指定的标准方法返回代码列表(第2.2.1.1节)被修改,特别是

  • 不使用OK代码来指示成功操作。成功或失败使用标准的Result类型来指示。
  • 不使用TIMEOUT代码。超时应表示为Result::ErrOption::None
  • 不应使用通用的ERROR代码,而应使用更具体的价值。
  • NO_DATA不使用。数据不存在应编码为Option::None

DataReader和DataWriter接口

DDS规范指定了多个函数来从DataReader中读取接收到的数据样本

  • read:从DataReader访问反序列化数据对象,并标记为已读取。如果请求已读取的样本,则可以再次读取相同的样本。
  • take:与read类似,但移除了从DataReader返回的对象,因此无法再次访问。
  • read_w_conditiontake_w_condition:读取/获取匹配指定条件的样本。
  • read_next_sampletake_next_sample:读取/获取下一个非先前访问的样本。
  • read_instancetake_instance:读取/获取属于单个实例(具有相同键)的样本。
  • read_next_instancetake_next_instance_next_instance的组合。
  • read_next_instance_w_conditiontake_next_instance_w_condition:是 _next_instance_w_condition 的组合。

我们决定不实现这12个中的全部。相反,我们实现了一组更小的方法。

  • read:从 DataReader 中借用数据。
  • take:将数据从 DataReader 移动。
  • read_instancetake_instance:访问属于单个键的样本。

上述所有方法都需要 ReadCondition 来指定要访问的样本,但指定“任何”条件,即无条件访问,非常简单。

还有 read_next_sampletake_next_sample 方法,但这些都是 read/take 的简化包装器。

除了这些,我们还提供 Rust Iterator 接口来读取数据。

内存管理

DDS 规范指定在手动内存管理方面的操作,即许多对象类型通过 create_ 方法调用创建,并通过匹配的 delete_ 方法调用销毁。我们选择在可能的情况下依赖 Rust 内存管理,包括处理有效载荷数据。

基于 rtps-rs

这里使用的 RTPS 实现源自 rtps-rs

依赖关系

~6–23MB
~329K SLoC