Repository navigation
Send Policy
可用状态: 已包含在 1.1.0 中,于 2026 年 10 月 3 日发布。实测实现来自 8c06cf4,目前已包含在公开发布版中;旧版本不提供此 feature。
在已发布 crate 上启用 feature:
[dependencies]
rust-raknet = { version = "1.4.0", features = ["send-policy"] }feature 提供 SendOptions、SendOptionsError、set_send_options 和 send_options,但不会自动启用每个 socket 的策略。
use rust_raknet::{RaknetSocket, SendOptions};
async fn configure(socket: &RaknetSocket) -> Result<(), Box<dyn std::error::Error>> {
let options = SendOptions::default()
.with_in_flight_limits(64, 256 * 1024)?
.with_queue_budgets(256 * 1024, 64 * 1024)?
.with_flush_budget(256 * 1024)?;
socket.set_send_options(options).await?;
assert_eq!(socket.send_options().await, Some(options));
Ok(())
}在开始批量发送前,对客户端已连接 socket 和服务端 accept 得到的 socket 分别配置。同一连接的克隆共享配置。启用 feature 但未配置时,查询返回 None;默认构建不编译策略状态和检查,也不提供这些方法。
上面的 configure 函数可以在连接成功后立即调用:
let address: std::net::SocketAddr = "127.0.0.1:19132".parse()?;
let client = RaknetSocket::connect(&address).await?;
configure(&client).await?;服务端应在 accept 后、启动发送任务前配置每条连接。它是 socket 接口,不是 listener 配置项:
let client = listener.accept().await?;
configure(&client).await?;反向代理接受的前端连接和主动连接的上游是两条独立连接。如果两端发送都需要策略,应分别配置;只设置一端不会影响另一端,也不会与对端协商策略。
let frontend = listener.accept().await?;
let upstream = RaknetSocket::connect(&upstream_address).await?;
configure(&frontend).await?;
configure(&upstream).await?;片段假设 listener 已开始监听、需要时已有上游 SocketAddr,并位于可传播错误的 async 函数中。配置改变后续接纳与调度,不改变消息可靠性;每次 send 仍需选择 Reliability。
修改一项限制时,保留其他配置:
let previous = socket.send_options().await.unwrap_or_default();
let updated = previous.with_in_flight_limits(32, 64 * 1024)?;
socket.set_send_options(updated).await?;未配置的连接会因此启用策略;已配置连接保留没有修改的队列和 flush 预算。调低限制不会丢弃已接纳消息或已有在途帧,随着旧工作排空才按更严格限制接纳。对端仍可能收到先前接纳数据的短暂突发,所以这不是立即生效的网络速率限制器。
目前没有禁用/恢复未配置状态的接口。set_send_options(SendOptions::default()) 是应用预设,不是关闭调度器。新的未配置 socket 使用原有策略;不启用 feature 的构建才完全不编译策略代码。
| 目标 | 起点 | 需要观察 |
|---|---|---|
| 只有可靠流量,优先吞吐 | 默认构建,不调用策略 setter | 不需要连接级控制时,没有必要增加策略成本 |
| 可靠流量混合实时更新 | 显式 SendOptions::default(),独立发送任务 |
除已到达消息延迟外,也看更新到达率和可靠吞吐 |
| 减少可靠在途数据 | 每次只调小帧数或字节上限 | 健康高 RTT 吞吐可能下降;丢包本身不等于队列拥塞 |
| 缩小发送突发 | 谨慎调低 flush_bytes
|
剩余帧可能等到下一次 send、ACK 或维护 tick |
| 接纳更多排队工作 | 调整可靠软预算或不可靠预留 | 排队延迟、内存与应用背压;这不是带宽比例分配 |
帧数和字节上限同时生效,先达到哪一个就停止新增可靠在途数据。粗略起点可参考带宽 × RTT 的在途字节量(100 Mbps × 30 ms ≈ 375000 B),但它不是自动控制器;应用窗口、ACK 行为、编码开销和共享瓶颈仍会影响结果。队列预算与在途限制也不是同一约束。
前面示例的 256 KiB 在途字节上限是自定义配置。benchmark 策略列使用 SendOptions::default(),该值为 64 MiB,不要将其测量结果直接套用于 256 KiB 配置。
| 限制 | SendOptions::default() |
含义 |
|---|---|---|
| 可靠在途帧 | 64 帧 | 包括分片与合包中分别计数的可靠帧 |
| 可靠在途字节 | 64 MiB | 编码后的帧字节,含帧集合头 |
| 可靠队列软预算 | 256 KiB | 待发及未确认的可靠数据与估算元数据 |
| 不可靠队列预留 | 64 KiB | 独立待发预算,新接纳的可靠数据必须留下这部分空间 |
| 单次 flush 预算 | 256 KiB | 一次配置调度返回的编码帧字节突发上限 |
帧上限允许 1–4096;在途和 flush 字节上限允许 2048 B–64 MiB。两个队列预算分别至少 2048 B,合计不超过 64 MiB。应用配置时还会检查协商 MTU。构造器返回 SendOptionsError,不兼容限制应用到 socket 时返回传输错误。
这些是记账限制,不是进程 RSS 或带宽上限。一次较大的可靠发送(包括批量发送)可以超过可靠软预算,但仍受 64 MiB 硬记账限制与不可靠预留约束。大于不可靠预留的批量发送按已有路径逐步发送,不要求整批同时放入队列。
配置后使用独立待发队列。不可靠预留有空间时,可靠在途窗口已满也不阻止接纳小型不可靠更新。flush 在不可靠帧、可靠重传和可靠新帧之间按字节轮转,并遵守在途和突发限制。
如果一个任务等待可靠发送容量时仍需发送实时更新,应使用不同发送任务。调度器不替换或静默驱逐已接纳的不可靠消息;网络仍可能丢包,UnreliableSequenced 仍遵守原来的序列过滤语义。
调低限制会保留已接纳消息,旧数据排空后才继续接纳。过小的 flush 预算可能把剩余工作推迟到下一次 send、ACK 或原有维护 tick;不会新增等待凑批的计时器。
线协议编码、五种可靠模式、分片、ACK/NACK 和重传规则保持不变,不增加对端协商。该策略不是自适应拥塞控制,不保证带宽比例,也不自动扩缩窗口。
小窗口可能减少瓶颈排队,也可能限制健康高 RTT 链路的吞吐,应根据实际负载测试选择,而不是认为越小越好。
10 月 3 日 benchmark把默认与显式配置的普通/批量构建,同 TCP、C KCP、quic-go 做了 623 次已校验测量,范围和内存均在表中。全部采用可靠有序回显,不用于衡量混合流量调度收益。
策略改变队列接纳和突发时机,在相关路径增加记账与调度工作。线协议不变不代表吞吐和较慢消息延迟不变;本组 benchmark 没有隔离每项变化的单一原因。启用 feature 但未配置的二进制也不是表里的默认构建。
| 可靠有序场景 | 默认构建 | 显式配置预设 | 中位数变化 |
|---|---|---|---|
| 单连接,800 B,无注入丢包,普通吞吐 | 185.57 MiB/s | 175.19 MiB/s | −5.6% |
| 1024 连接,800 B,无注入丢包,普通吞吐 | 464.75 MiB/s | 486.67 MiB/s | +4.7% |
| 1024 连接,800 B,无注入丢包,批量吞吐 | 481.91 MiB/s | 423.69 MiB/s | −12.1% |
| 1024 连接,64 B,无注入丢包,普通发送负载下的 99% RTT | 54.03 ms | 100.53 ms | +86.1%(更慢) |
这些是三轮中位数,完整范围与 RSS 在结果表中,不证明差异已具有统计显著性,也不表示通用提升。
另一组混合流量实验使用 8 个各持一条连接的进程,共享从 100 Mbps/30 ms RTT 降到 2 Mbps/800 ms RTT 的链路。候选发送端使用默认策略预设,分别饱和发送 896 B 可靠流,另一个任务以 100 Hz 发送 64 B 不可靠更新。拥塞阶段,已到达不可靠消息中较慢 1% 的单程延迟从 1894.73 到 743.49 ms,但可靠吞吐从 0.072704 到 0.059392 Mbps;全程不可靠消息到达率从 68.65% 到 60.01%。不能只看已到达消息的延迟,而忽略丢失消息和可靠带宽。
保持可选启用,混合流量使用独立发送任务,并测试实际消息大小、连接数与网络。增加缓冲或减小窗口都不保证吞吐与延迟同时改善。
默认和 feature 构建分别通过 118 项与 144 项测试,其中基础用例有重叠。Bedrock 26.52 自动握手/NetworkSettings 与代理检查通过 24/24;这些是协议检查,不是新一轮人工游戏操作测试。
English · 简体中文 · GitHub · crates.io 1.4.0 · Reviewed / 核对:2026-10-12 / b909c93
- Overview
- Quick start
- Blocking calls and shared runtimes
- Public API index
- Five reliability modes
- RakNet wire format and recovery
- Message lifecycle and limits
- Bytes and explicit batching
- Send policy
- Recovery policy and tail probes
- Every configuration parameter
- Concurrency and socket tuning
- Errors, deadlines and cancellation
- Congestion and deployment boundaries
- Benchmark results
- Benchmark methodology
- Benchmark reproduction
- Minecraft Bedrock proxy
- Troubleshooting and development
- Release history and upgrading