| Crates.io | tokio-raknet |
| lib.rs | tokio-raknet |
| version | 0.2.0 |
| created_at | 2025-11-30 09:33:12.132877+00 |
| updated_at | 2025-12-03 05:21:06.604413+00 |
| description | A high-performance, asynchronous implementation of the RakNet protocol on top of Tokio. |
| homepage | |
| repository | https://github.com/jvigu/tokio-raknet |
| max_upload_size | |
| id | 1958056 |
| size | 287,596 |
tokio-raknet is a high-performance, asynchronous implementation of the RakNet protocol written in pure Rust. Built on top of the Tokio runtime, it is designed to provide a modern, ergonomic API for building robust UDP-based networked applications, games (including Minecraft: Bedrock Edition), and services.
async/await for high concurrency.RaknetListenerConfig and RaknetStreamConfig.tracing for low-overhead debugging and performance profiling.Add this to your Cargo.toml:
[dependencies]
tokio = { version = "1", features = ["full"] }
tokio-raknet = "0.1"
bytes = "1"
Connecting to a server is straightforward. The client handles the offline handshake, MTU negotiation, and session setup automatically.
use tokio_raknet::transport::RaknetStream;
use bytes::Bytes;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Connect to a RakNet server (default config)
let mut client = RaknetStream::connect("127.0.0.1:19132".parse()?).await?;
println!("Connected!");
// Send a message (defaults to ReliableOrdered)
client.send("Hello, Server!").await?;
// Receive packets
while let Some(result) = client.recv().await {
match result {
Ok(packet) => println!("Received: {:?}", packet),
Err(e) => {
eprintln!("Connection lost: {:?}", e);
break;
}
}
}
Ok(())
}
The RaknetListener works similarly to a TcpListener, providing a stream of incoming connections.
use tokio_raknet::transport::RaknetListener;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Bind the listener (default config)
let mut listener = RaknetListener::bind("0.0.0.0:19132".parse()?).await?;
println!("Listening on 0.0.0.0:19132");
// Accept connections loop
while let Some(mut conn) = listener.accept().await {
tokio::spawn(async move {
println!("New connection from {}", conn.peer_addr());
// Echo loop
while let Some(result) = conn.recv().await {
match result {
Ok(packet) => {
// Echo back
if let Err(_) = conn.send(packet).await {
break;
}
}
Err(e) => {
println!("Lost connection to {}: {:?}", conn.peer_addr(), e);
break;
}
}
}
});
}
Ok(())
}
You can customize the behavior of clients and listeners using RaknetStreamConfig and RaknetListenerConfig. This allows tuning for specific network conditions or security requirements.
Client with Custom MTU and Timeout:
use tokio_raknet::transport::{RaknetStream, RaknetStreamConfig};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = RaknetStreamConfig {
mtu: 1492, // Try to negotiate a larger MTU
connection_timeout: Duration::from_secs(5),
..Default::default()
};
let client = RaknetStream::connect_with_config("127.0.0.1:19132".parse()?, config).await?;
// ...
Ok(())
}
Server with Connection Limits:
use tokio_raknet::transport::{RaknetListener, RaknetListenerConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = RaknetListenerConfig {
max_connections: 100,
max_pending_connections: 50, // Limit handshakes to prevent flooding
max_queued_reliable_bytes: 2 * 1024 * 1024, // 2MB limit per session
advertisement: b"My Secure Server".to_vec(),
..Default::default()
};
let listener = RaknetListener::bind_with_config("0.0.0.0:19132".parse()?, config).await?;
// ...
Ok(())
}
For games and real-time applications, you often need fine-grained control over how packets are delivered. The Message struct allows you to configure reliability, ordering channels, and priority.
use tokio_raknet::transport::RaknetStream;
use tokio_raknet::protocol::{reliability::Reliability, state::RakPriority};
use tokio_raknet::transport::Message;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = RaknetStream::connect("127.0.0.1:19132".parse()?).await?;
// Send a packet that can be lost (Unreliable), but is immediate
let movement_update = Message::new(vec![0x01, 0x02])
.reliability(Reliability::Unreliable)
.priority(RakPriority::Immediate);
client.send(movement_update).await?;
// Send a chat message that MUST arrive, and in order (ReliableOrdered)
// on channel 1 to avoid blocking movement data on channel 0.
let chat_msg = Message::new("Hello world")
.reliability(Reliability::ReliableOrdered)
.channel(1);
client.send(chat_msg).await?;
Ok(())
}
We provide several fully runnable examples in the examples/ directory:
basic_ping: A minimal server/client setup exchanging simple text payloads.ping_pong: Shows back-and-forth communication latency.minecraft_start: Demonstrates connecting to a real Minecraft: Bedrock Edition server (verifies handshake and MTU negotiation).To run an example:
cargo run --example basic_ping
Contributions are welcome! Please ensure that any changes pass existing tests and include new tests where appropriate. This project uses standard cargo fmt and cargo clippy settings.
This project is licensed under the MIT License.