Skip to content

This project demonstrates how to add TCP-like reliability guarantees (acknowledgments, retransmission, ordering) to UDP's speed and simplicity.

Notifications You must be signed in to change notification settings

AlphaR2/Relic-UDP

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Relic-UDP --- A Simple Reliable UDP Implementation

This is a sample learning project where I delved into the working principles of the network & transport layer with particular focus on the UDP(User Datagram Protocol).

This project demonstrates how to add TCP-like reliability guarantees (acknowledgments, retransmission, ordering) to UDP's speed and simplicity.

The aim is to create a rust project that uses tokio and async rust to test and understand how UDP works and then improve on its shortcomings

Why This Exists

This is an educational project designed to build deep understanding of:

  • Transport layer protocols (TCP, UDP, QUIC)
  • Network reliability mechanisms (sequence numbers, ACKs, timeouts)
  • Async networking in Rust (Tokio, async/await)
  • Blockchain networking fundamentals (Solana validator communication, gossip protocols) By building reliability from scratch, I gain insight into how production protocols like QUIC work and how Solana validators communicate efficiently.

How It Works

This is a reliable UDP implemetation that gives the speed of UDP together with reliablity, retransmission and certainty of TCP. In Relic UDP we have:

  • Sequence numbers for packet ordering
  • Acknowledgments (ACKs) to confirm delivery
  • Timeouts & retransmission for handling packet loss
  • Flow control for managing sender/receiver speeds

UDP is connectionless, stateless and fast. There are short comings while using UDP, like packet rearrangement, loss etc. So Relic UDP will contain retransmission, Acknowledgement as well as speed

Architecture

┌─────────────┐                    ┌─────────────┐
│   Client    │                    │   Server    │
│             │                    │             │
│  Protocol   │ ←──── UDP ────→    │  Protocol   │
│   Layer     │   (unreliable)     │   Layer     │
│             │                    │             │
│  Tokio UDP  │                    │  Tokio UDP  │
│   Socket    │                    │   Socket    │
└─────────────┘                    └─────────────┘

Components:

  • protocol.rs: Packet serialization/deserialization, message types
  • client.rs: Sender logic with retransmission
  • server.rs: Receiver logic with ACK generation

Key Concepts

  • Sequence Numbers: Each packet gets a unique number to track order and detect duplicates/loss
  • Acknowledgments (ACKs): Receiver confirms each packet received by sending ACK with sequence number
  • Timeouts: If no ACK received within timeout period, sender retransmits the packet
  • Retransmission: Lost packets are automatically resent based on timeout or negative ACK

Features

Implemented:

  • Basic UDP client/server communication
  • Packet structure with sequence numbers
  • Serialization/deserialization (to_bytes/from_bytes)
  • Unit tests for protocol layer

In Progress:

  • ACK message type
  • Timeout & retransmission logic
  • Packet loss simulation

Future:

  • Go-Back-N sliding window protocol
  • Selective Repeat ARQ
  • Flow control (window size management)
  • Congestion control
  • Custom UDP implementation from scratch (using tun/tap)

Prerequisites

  • Rust 1.70+ (with Cargo)
  • Linux/macOS/WSL (for full feature support)

Installation

git clone https://github.com/AlphaR2/Relic-UDP.git
cd Relic-UDP
cargo build

Running the Server

cargo run --bin server

Expected output:

=================================
🚀 RELIABLE UDP SERVER
=================================

Server listening on: 127.0.0.1:8080

RECEIVED Packet #1 from 127.0.0.1:xxxxx
Data: "Hello from packet #1"
ECHOED Packet #1 back

Running the Client

# In a separate terminal
cargo run --bin client

Expected output:

=================================
📡 RELIABLE UDP CLIENT
=================================

Client: 127.0.0.1:xxxxx
Server: 127.0.0.1:8080

SENDING Packet #1: Hello from packet #1
RECEIVED Packet #1: "Hello from packet #1"

SENDING Packet #2: Hello from packet #2
RECEIVED Packet #2: "Hello from packet #2"
...
All packets sent successfully!

Protocol Specification

Packet Format

Current implementation (Data packet):

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                      Sequence Number (u32)                    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Data (variable length)                     |
|                             ...                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • Sequence Number: 4 bytes (big-endian), tracks packet order
  • Data: Variable length payload (text, binary, any data)

Message Types

Current:

  1. DATA Packet: Contains sequence number + payload data

Coming: 2. ACK Packet: Acknowledgment with sequence number 3. NACK Packet: Negative acknowledgment for explicit retransmission

Protocol Flow

Basic Echo (Current):

Client                           Server
  |                                 |
  |-----DATA Packet #1------------->|
  |   [seq: 1, data: "Hello"]       |
  |                                 |
  |<----Echo Packet #1--------------|
  |   [seq: 1, data: "Hello"]       |
  |                                 |

With ACKs (Next Phase):

Client                           Server
  |                                 |
  |-----DATA Packet #1------------->|
  |   [seq: 1, data: "Hello"]       |
  |                                 |
  |<----ACK #1----------------------|
  |                                 |
  |-----DATA Packet #2------------->|
  |   [seq: 2, data: "World"]       |
  |                                 |
  |<----ACK #2----------------------|
  |                                 |

Testing

# Run all tests
cargo test

# Run with output
cargo test -- --nocapture

# Test specific module
cargo test protocol::tests

Current tests:

  • test_packet_seri_deseri: Verifies packet serialization round-trip
  • test_packet_with_empty_data: Tests edge case of empty payload

Technical Decisions

Why UDP?

Speed over guarantees:

  • No connection establishment overhead (vs TCP's 3-way handshake)
  • Lower latency for time-sensitive applications
  • Full control over reliability mechanism
  • Matches Solana's networking approach (QUIC on UDP)

Learning opportunity:

  • Understand the problems UDP has (packet loss, reordering, duplication)
  • Implement solutions used in production protocols
  • Appreciate what TCP provides for free

Why This Reliability Approach?

Stop-and-Wait (Current):

  • Simplest to implement and understand
  • Send one packet, wait for ACK, send next
  • Great for learning fundamentals

Sliding Window (Future):

  • Much better performance (send multiple packets before waiting)
  • Used by TCP, QUIC, and other production protocols
  • More complex but necessary for real-world use

Challenges Faced - Working on a fix

1. Packet Buffering Issues

  • Problem: Client receiving old packets from OS buffer
  • Cause: UDP socket buffers incoming packets in kernel FIFO queue
  • Learning: Discovered why sequence number checking is critical
  • Solution: Next phase will implement ACK verification loop

2. Serialization Design

  • Problem: Converting Rust structs to/from network bytes
  • Solution: Used big-endian encoding for network byte order
  • Learning: Understood why protocols specify byte order

3. Async Rust Learning Curve

  • Problem: Understanding futures, .await, and Tokio runtime
  • Solution: Started with simple examples, gradually added complexity
  • Learning: Async is necessary for high-performance network code

Current Phase

Phase 2 Complete: Sequence Numbers

  • Implemented Packet struct with seq_num field
  • Built serialization/deserialization (to_bytes/from_bytes)
  • Client sends numbered packets (1, 2, 3, 4, 5)
  • Server decodes and echoes back with sequence numbers
  • Discovered UDP buffering behavior

Phase 3 Next: ACKs & Verification

  • Add Message enum (Data vs Ack)
  • Server sends ACK after receiving packet
  • Client waits for correct ACK before proceeding
  • Implement ACK timeout and retry logic

Roadmap

Phase 1: Basic UDP (Complete)

  • UDP echo server/client
  • Tokio async networking
  • Send/receive raw bytes

Phase 2: Sequence Numbers (Complete)

  • Packet structure with seq_num
  • Serialization/deserialization
  • Numbered packet transmission

Phase 3: ACKs (In Progress)

  • ACK message type
  • Sequence number verification
  • Correct packet ordering

Phase 4: Timeouts & Retransmission

  • Timeout detection
  • Automatic retransmission
  • Retry limits

Phase 5: Sliding Window

  • Go-Back-N protocol
  • Multiple outstanding packets
  • Window size management

Phase 6: Advanced Features

  • Flow control
  • Congestion control
  • Performance optimization

Phase 7: Deep Dive

  • Build UDP from scratch using tun/tap
  • Implement IP layer
  • Packet fragmentation

Real-World Connections

Similar Protocols

TCP

  • Similarities: Both use sequence numbers, ACKs, retransmission
  • Differences: TCP has connection state, more overhead, automatic flow control
  • Relic-UDP: Lighter weight, explicit control over reliability

QUIC

  • Similarities: UDP-based, multiplexing, modern design
  • Differences: QUIC has encryption (TLS 1.3), connection migration, 0-RTT
  • Relic-UDP: Educational simplification of QUIC concepts

TFTP

  • Similarities: Simple reliable UDP, stop-and-wait protocol
  • Differences: TFTP is for file transfer only
  • Relic-UDP: General-purpose protocol learning

Solana Connection

Why this matters for Solana(My major focus):

  1. Validator Networking: Solana uses QUIC (UDP-based) for transaction ingestion (TPU)
  2. Turbine Protocol: Block propagation uses UDP with erasure coding
  3. Gossip: Validator discovery and comm protocol
  4. Performance: Understanding UDP is key to understanding Solana's speed

Learning Resources

Networking Fundamentals:

Async Rust:

Performance

Benchmarks coming in Phase 4 after timeout/retransmission

Planned metrics:

  • Throughput vs TCP (Mbps)
  • Latency comparison (RTT)
  • Packet loss resilience (% loss vs delivery rate)

Project Structure

relic-udp/
├── src/
│   ├── server.rs      # UDP server with packet decoding and echo
│   ├── client.rs      # UDP client with numbered packet sending
│   └── protocol.rs    # Packet struct, serialization, and tests
├── Cargo.toml         # Dependencies (tokio)
├── README.md          # This file
└── .gitignore

Status: 🚧 Active Development | Phase 2 Complete | Learning in Public

Last updated: 11/17/2025# Relic-UDP

About

This project demonstrates how to add TCP-like reliability guarantees (acknowledgments, retransmission, ordering) to UDP's speed and simplicity.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages