| Crates.io | bitfold |
| lib.rs | bitfold |
| version | 0.1.5 |
| created_at | 2025-11-02 06:46:29.370478+00 |
| updated_at | 2025-12-06 22:25:36.696549+00 |
| description | A modern, high-performance reliable UDP networking library inspired by ENet, built with Rust |
| homepage | https://github.com/russellwmy/bitfold |
| repository | https://github.com/russellwmy/bitfold |
| max_upload_size | |
| id | 1912744 |
| size | 73,254 |
A modern, high-performance reliable UDP networking library for Rust, inspired by ENet.
Bitfold provides flexible delivery guarantees, automatic fragmentation, congestion control, and multi-channel communication—ideal for games, real-time applications, and high-performance network services.
UDP performance with TCP-like reliability when you need it.
Traditional networking presents a trade-off: TCP offers reliability but with high latency and head-of-line blocking, while UDP offers low latency but no guarantees. Bitfold gives you the best of both worlds:
Built-in utilities for common networking tasks:
Add Bitfold to your Cargo.toml:
[dependencies]
bitfold = "0.1"
use bitfold::{Host, Packet, SocketEvent};
use std::time::Instant;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Bind to a local address
let mut host = Host::bind("0.0.0.0:9000")?;
println!("Server listening on 0.0.0.0:9000");
loop {
// Update internal state (timers, retransmissions, etc.)
host.manual_poll(Instant::now());
// Process incoming events
while let Some(event) = host.recv() {
match event {
SocketEvent::Connect(addr) => {
println!("Client connected: {}", addr);
}
SocketEvent::Packet(packet) => {
println!("Received from {}: {:?}",
packet.addr(),
String::from_utf8_lossy(packet.payload()));
// Echo back
host.send(Packet::reliable_unordered(
packet.addr(),
packet.payload().to_vec()
))?;
}
SocketEvent::Disconnect(addr) => {
println!("Client disconnected: {}", addr);
}
SocketEvent::Timeout(addr) => {
println!("Client timeout: {}", addr);
}
}
}
}
}
use bitfold::{Host, Packet};
use std::time::Instant;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut host = Host::bind_any()?;
let server_addr = "127.0.0.1:9000".parse()?;
// Send initial message
host.send(Packet::reliable_unordered(
server_addr,
b"Hello, server!".to_vec()
))?;
loop {
host.manual_poll(Instant::now());
while let Some(event) = host.recv() {
// Handle events
println!("Received event: {:?}", event);
}
}
}
Bitfold offers five delivery modes, each optimized for different use cases:
Best for: High-frequency position updates, non-critical state
let packet = Packet::unreliable(addr, data);
Best for: Important events that can arrive in any order
let packet = Packet::reliable_unordered(addr, data);
Best for: Critical sequential data (TCP-like)
let packet = Packet::reliable_ordered(addr, data, None);
Best for: State updates where only the latest matters
let packet = Packet::reliable_sequenced(addr, data, None);
Best for: One-time events that can be reordered
let packet = Packet::unsequenced(addr, data);
Channels allow you to separate different traffic types with independent ordering guarantees. This prevents head-of-line blocking across different data streams.
use bitfold::{Config, Host, Packet};
// Configure 4 independent channels
let mut config = Config::default();
config.channel_count = 4;
let mut host = Host::bind_with_config("0.0.0.0:7777", config)?;
// Each channel has independent ordering
host.send(Packet::reliable_ordered_on_channel(addr, player_input, 0, None))?;
host.send(Packet::unreliable_on_channel(addr, world_state, 1))?;
host.send(Packet::reliable_ordered_on_channel(addr, chat_message, 2, None))?;
host.send(Packet::reliable_sequenced_on_channel(addr, animation, 3, None))?;
| Channel | Type | Delivery | Use Case |
|---|---|---|---|
| 0 | Critical | Reliable Ordered | Player commands, RPC calls |
| 1 | State | Unreliable | Entity positions, physics state |
| 2 | Messages | Reliable Ordered | Chat, notifications |
| 3 | Effects | Reliable Sequenced | Animations, UI updates |
Bitfold is highly configurable to suit your application's needs:
use bitfold::{Config, CompressionAlgorithm};
use std::time::Duration;
let mut config = Config::default();
// Connection Settings
config.idle_connection_timeout = Duration::from_secs(30);
config.heartbeat_interval = Some(Duration::from_secs(5));
// Multi-Channel Configuration
config.channel_count = 8; // Up to 255 channels
// Fragmentation & MTU
config.max_packet_size = 32 * 1024; // Maximum packet size (32 KB)
config.use_pmtu_discovery = true; // Enable PMTU discovery (default)
config.pmtu_min = 576; // Minimum MTU (IPv4 safe)
config.pmtu_max = 1400; // Maximum MTU
config.pmtu_interval_ms = 5000; // Probe interval
// Flow Control
config.initial_window_size = 64; // Initial window in packets
config.min_window_size = 16; // Minimum window
config.max_window_size = 256; // Maximum window
// Bandwidth Limiting (0 = unlimited)
config.outgoing_bandwidth_limit = 0; // Bytes per second
config.incoming_bandwidth_limit = 0; // Bytes per second
// Compression (optional)
config.compression = CompressionAlgorithm::Lz4; // None, Lz4, or Zlib
config.compression_threshold = 128; // Compress if > 128 bytes
// Data Integrity (optional)
config.use_checksums = true; // Enable CRC32 checksums
// Congestion Control
config.rtt_smoothing_factor = 0.125; // RTT estimation smoothing
let host = Host::bind_with_config("0.0.0.0:7777", config)?;
// Low-latency gaming (minimal reliability)
let mut config = Config::default();
config.use_pmtu_discovery = true;
config.compression = CompressionAlgorithm::None;
config.use_checksums = false;
// Reliable messaging (maximum reliability)
let mut config = Config::default();
config.use_checksums = true;
config.compression = CompressionAlgorithm::Lz4;
config.initial_window_size = 128;
// Bandwidth-constrained (mobile/embedded)
let mut config = Config::default();
config.outgoing_bandwidth_limit = 100_000; // 100 KB/s
config.compression = CompressionAlgorithm::Lz4;
config.pmtu_max = 1200;
Bitfold includes built-in utilities for common networking operations:
use bitfold::utilities;
// DNS Resolution
let addr = utilities::resolve_host("example.com", 8080)?;
println!("Resolved to: {}", addr);
// Reverse DNS Lookup
use std::net::{IpAddr, Ipv4Addr};
let ip = IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8));
let hostname = utilities::reverse_lookup(&ip)?;
println!("Hostname: {}", hostname);
// IP Parsing
let addr = utilities::parse_ip("192.168.1.1", 9000)?;
println!("Socket address: {}", addr);
// IP Formatting
use std::net::SocketAddr;
let addr: SocketAddr = "127.0.0.1:8080".parse()?;
let ip_str = utilities::format_ip(&addr);
println!("IP: {}", ip_str); // "127.0.0.1"
The repository includes working examples for common scenarios:
cargo run --example server -- 127.0.0.1:7777
cargo run --example client -- 127.0.0.1:7777
The examples demonstrate:
Bitfold supports two polling modes to fit different application architectures:
use std::{thread, time::{Duration, Instant}};
use bitfold::Host;
let mut host = Host::bind_any()?;
let frame_duration = Duration::from_millis(16); // 60 FPS
loop {
let frame_start = Instant::now();
// Update Bitfold state
host.manual_poll(frame_start);
// Process all pending events
while let Some(event) = host.recv() {
// Handle event
}
// Your game/application logic here
update_game_state();
render_frame();
// Maintain frame rate
let elapsed = frame_start.elapsed();
if elapsed < frame_duration {
thread::sleep(frame_duration - elapsed);
}
}
use std::thread;
use bitfold::Host;
let mut host = Host::bind_any()?;
let event_rx = host.get_event_receiver();
// Start background polling thread (polls every 1ms)
thread::spawn(move || {
host.start_polling();
});
// Main thread processes events
for event in event_rx.iter() {
match event {
// Handle events asynchronously
}
}
use tokio::time::{interval, Duration};
use bitfold::Host;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut host = Host::bind_any()?;
let mut tick = interval(Duration::from_millis(1));
loop {
tick.tick().await;
host.manual_poll(std::time::Instant::now());
while let Some(event) = host.recv() {
// Handle event
}
}
}
Bitfold uses a modular workspace architecture with clear separation of concerns:
bitfold/
├── core - Configuration, types, utilities, memory pooling
├── protocol - Pure protocol logic (no I/O)
│ ├── Packet encoding/decoding
│ ├── Acknowledgment handling
│ ├── Congestion control
│ ├── Compression (LZ4, Zlib)
│ └── CRC32 checksums
├── peer - Per-peer state machine
│ ├── Command queuing & batching
│ ├── Flow control (sliding window)
│ ├── Fragment reassembly
│ ├── PMTU discovery
│ └── Statistics tracking
└── host - Socket I/O and session management
├── UDP socket handling
├── Multi-peer coordination
├── Event emission
└── Polling modes
bitfold (facade)
↓
bitfold-host (I/O layer)
↓
bitfold-peer (state machine)
↓
bitfold-protocol (pure protocol logic)
↓
bitfold-core (foundation)
For detailed architecture documentation, see WORKSPACE.md.
// High-frequency updates → Unreliable
host.send(Packet::unreliable(addr, position_data))?;
// Important events → Reliable Unordered
host.send(Packet::reliable_unordered(addr, damage_event))?;
// Sequential messages → Reliable Ordered
host.send(Packet::reliable_ordered(addr, chat_msg, None))?;
// Latest state only → Reliable Sequenced
host.send(Packet::reliable_sequenced(addr, animation_state, None))?;
const CHANNEL_COMMANDS: u8 = 0;
const CHANNEL_STATE: u8 = 1;
const CHANNEL_CHAT: u8 = 2;
// Prevents chat messages from blocking game state
host.send(Packet::reliable_ordered_on_channel(addr, msg, CHANNEL_CHAT, None))?;
// Default is already enabled, but you can configure it
config.use_pmtu_discovery = true; // Automatically finds optimal MTU
config.pmtu_min = 576; // IPv4 minimum
config.pmtu_max = 1400; // Safe for most networks
// Call at least once per frame (16ms for 60 FPS)
host.manual_poll(Instant::now());
// More frequent polling = lower latency
// 1ms polling is recommended for real-time applications
// Call periodically in long-running applications (once per second)
let now = Instant::now();
for (_addr, peer) in host.peers_mut() {
peer.cleanup_stale_fragments(now);
}
for (addr, peer) in host.peers() {
let stats = peer.statistics();
println!("{}: RTT={}ms, Loss={:.2}%",
addr,
stats.rtt(),
stats.packet_loss_rate() * 100.0
);
}
config.compression = CompressionAlgorithm::Lz4;
config.compression_threshold = 128;
config.outgoing_bandwidth_limit = 100_000; // 100 KB/s
config.use_checksums = true; // Detect data corruption
Bitfold is designed for high performance:
Typical performance on a modern system (i7-9700K, 1Gbps LAN):
Run the test suite:
# Run all tests
cargo test --workspace
# Run tests for a specific package
cargo test -p bitfold-core
cargo test -p bitfold-protocol
cargo test -p bitfold-peer
# Run with verbose output
cargo test -- --nocapture
# Run doc tests
cargo test --doc
# Format code
cargo fmt --all
# Lint code
cargo clippy --workspace --all-targets
# Check without building
cargo check --workspace
# Generate documentation
cargo doc --workspace --open
We code with AI. All implementation is done through AI-assisted development to maintain consistency and quality.
clippy.toml, .rustfmt.toml, CI/CD, documentation)Please include:
rustc --version)This project is licensed under the MIT License. See the LICENSE file for details.
Bitfold is inspired by ENet, a proven reliable UDP library used in thousands of games and applications. We've modernized the concepts for Rust's ownership model and added features requested by the community.