Repository navigation
Batching EN
For small messages, frame processing, system calls and scheduling can dominate the cost. A standard RakNet frame set can carry multiple complete frames, reducing datagram count while preserving application message boundaries.
use rust_raknet::{RaknetSocket, Reliability, error::Result};
async fn send_ready(socket: &RaknetSocket) -> Result<()> {
let first: &[u8] = &[0xfe, 1, 10];
let second: &[u8] = &[0xfe, 2, 20];
socket.send_batch(&[first, second], Reliability::ReliableOrdered).await
}The owned-buffer API uses rust_raknet::Bytes: send_bytes_batch(&[Bytes], Reliability). Both borrowed and owned APIs have *_with_order_channel variants.
- A multi-message batch call uses
ReliableOrdered. - Messages do not require fragmentation, and adjacent messages plus frame headers fit the negotiated MTU.
- A datagram carries at most 8 messages, further limited by MTU. One API call may contain more messages.
- Only ready messages are processed: there is no timer waiting to fill a batch.
- Other modes, fragments and messages that do not fit retain individual datagrams. Two 800 B messages cannot fit together at the default MTU.
An effective NACK matching outstanding data or a reliable retransmission timeout permanently disables coalescing for that connection, until reconnecting. Loss during warmup affects later measurement phases too.
A fresh connection using only ordinary send() does not proactively enable coalescing; it sends promptly. Once a suitable batch call enables coalescing on that connection, queued messages from later ordinary calls may also participate. This does not introduce a timer to collect them.
Compare ordinary and batch APIs on fresh, separate connections. Do not benchmark ordinary sends by reusing a connection that already used batching.
use rust_raknet::{RaknetSocket, Reliability, error::Result};
async fn forward(source: &RaknetSocket, destination: &RaknetSocket) -> Result<()> {
let mut messages = Vec::with_capacity(8);
loop {
source.recv_bytes_batch(&mut messages, 8).await?;
destination.send_bytes_batch(&messages, Reliability::ReliableOrdered).await?;
}
}recv_batch() / recv_bytes_batch() clear the output, wait for the first message, then drain only messages already available. A zero limit returns immediately; a call takes at most 64 messages. A bidirectional proxy must run both directions concurrently; see the repository proxy example.
Bytes shares immutable data and reduces application payload copies for forwarding and retransmission queues. It is not end-to-end zero-copy networking.
Batch members are validated first, but cancellation during sending can leave a prefix sent or queued. A batch is not a transaction.
Test sustained small-message workloads. Sparse traffic and larger messages may not benefit. Examine throughput, typical latency, the slowest 1% of messages and memory. In the README, batching is faster for 64 B / 1,024 connections / no injected loss, while ordinary sends are faster for 800 B / 1,024 connections.
Keep three mechanisms separate: application message coalescing, UDP sendmmsg system-call batching and optional recvmmsg receive batching. They reduce different costs.
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