3 个不稳定版本
新版本 0.7.0 |
|
---|---|
0.7.0-alpha.2 | 2024年8月16日 |
0.7.0-alpha.1 | 2024年7月30日 |
0.6.0 | 2024年7月30日 |
#466 在 游戏开发
每月下载量:355
在 aeronet_webtransport 中使用
235KB
3.5K SLoC
aeronet_proto
为aeronet传输提供协议级功能实现。
由于不是所有底层传输都会提供相同的功能保证,这个crate提供了一些对底层协议无关的、无I/O的特定功能实现。
功能
功能 | 描述 | aeronet_proto |
---|---|---|
缓冲 | 将小的消息合并成一个大的数据包(类似于Nagle算法) | ✅ |
分片 | 大消息使用多个数据包发送 | ✅ |
通道管理 | 消息可以通过不同的通道发送,并具有不同的保证 | ✅ |
可靠性 | 可靠发送的消息将确保被对端接收到 | ✅ |
排序 | 接收到的消息将以发送时的顺序接收 | ✅ |
帧定界 | API维护消息边界(即不仅仅是一串字节流) | - |
加密 | 未经授权的第三方无法读取传输中的网络数据 | - |
身份验证 | 只有被授权使用此应用的用户才能连接 | - |
验证 | 消息在传输过程中没有被篡改或损坏 | - |
拥塞控制 | 控制数据发送的速度,以避免网络拥塞 | - |
协商 | 确保在对话之前两个对端都在使用相同的协议 | - |
客户端始终作为发起者,发送第一条消息。
未标记为该crate提供的功能必须在传输实现级别实现。例如,WebTransport默认加密连接,因此在aeronet_proto
级别实现加密是没有意义的。
如果传输已经支持协议提供的功能,建议使用协议的实现,因为这样可以使API在不同传输实现之间更加一致。例如,QUIC/WebTransport通过其流机制提供可靠性和排序,但是这些不支持与aeronet_proto
完全相同的特征集,因此不使用。
可视化工具
功能标志:visualizer
可视化器是一个集成在crate中的调试工具,它使用egui
和egui_plot
来显示网络统计数据的图表。它与任何使用Session
(参见SessionBacked
)的客户端传输兼容,也可以在Bevy中使用。
有关如何使用可视化器的说明,请参阅SessionStatsVisualizer
。
协议
该协议主要受Building a Game Network Protocol的启发,在术语和实现方面进行了一些调整。
术语
- 对等体:可以参与连接、发送或接收数据的实体。
- 消息:用户提供的字节缓冲区,用户希望将其发送给对等体。这是通过
aeronet
的-Transport
traits公开的最低级别的API类型。 - 数据包:可以作为一个单独的整体发送或接收的字节缓冲区。这是使用aeronet协议的实现必须关注的最低级别的API类型。
- 连接:用于在两个对等体之间传输原始数据字节的基础网络连接
- 会话:
Session
- 可以在连接上发送数据的同时使用在功能中概述的功能,例如分段、可靠性、排序
要求
aeronet协议可以在几乎所有传输之上使用。要求如下:
- 传输必须能够在对等体之间发送数据包,其中数据包定义为字节的可变长度序列
- 在传输后,数据包必须保证具有相同的 内容,而不会被截断或扩展
- 不需要保证可靠性、顺序或去重
布局
有关编码数据包布局的完整说明,请参阅[ty
]。
会话
API的入口点是Session
,它管理传入和传出消息,而无需执行任何I/O。可以使用Session::client
或Session::server
创建一个会话,并提供一个配置,该配置确定参数,例如最大数据包长度、发送/接收通道以及每秒可以发送多少字节。
API公开了以下主要功能:
Session::send
用于将消息缓冲起来以供稍后发送Session::flush
用于构建现在应发送的数据包Session::recv
用于接收传入的数据包并读取其数据Session::update
用于更新会话的内部状态,并检查我们是否使用了过多的内存(参见 内存管理)
内存管理
如果我们不限制会话使用的最大内存量,恶意节点可能会通过耗尽我们的所有内存来导致服务拒绝。因此,我们定义会话可以使用的最大内存量,并且如果使用过多内存,Session::update
将终止连接。
如果会话使用过多的内存
- 对端发送许多消息片段,但这些片段永远不会收到它们的最终片段
- 我们的端将被迫保留所有片段,直到它们完全重新组装
- 理论上,我们可能会丢弃属于不可靠通道的片段(这可能在以后实现),但我们永远不允许丢弃通过可靠通道发送的片段
- 对端永远不会确认我们的数据包
- 我们的端将被迫永远保留可靠消息的片段,因为我们必须重新发送它们,直到对端确认
MTU
最大可传输单元,或MTU,定义了单个数据包可能有多大(以字节为单位)。如果数据包长度超过MTU,则网络路径上的路由器可能会丢弃该数据包。为了避免这种情况,会话将永远不会产生一个大于用户指定的MTU的数据包。大于MTU的消息将被拆分成较小的片段,并在接收端重新组装(带有一些额外的开销,用于数据包和片段头)。
在创建会话时,您定义一个最小MTU和一个初始MTU。片段永远不会大于 min_mtu - OVERHEAD
,然而一个数据包永远不会大于 mtu
(由于接收器逻辑的工作方式,在连接期间无法更改片段的大小)。
然而,MTU可能会在连接的生命周期内发生变化,并且当有更高的路径MTU可用时,我们可以利用它,当它不再可行时减少MTU。为此,会话允许您通过 Session::set_mtu
来更改MTU。MTU永远不会低于 min_mtu
。
模糊测试
为了确保协议代码在所有情况下都能正常工作,我们既使用了单元测试也使用了模糊测试。模糊测试必须在Rust nightly上运行(在命令行中添加 +nightly
)。
要从 aeronet_proto/fuzz
目录启动模糊测试,请运行以下命令
cargo fuzz run <fuzz_target>
依赖关系
~4–13MB
~163K SLoC