RUDP uses ARQ alone by default. Optional Reed–Solomon FEC adds parity shards to outgoing datagrams, allowing recovery before a retransmission arrives. ARQ still retransmits anything FEC cannot recover. The bundled header-only engine requires neither Python nor an additional linked library.
flowchart LR
A[Application message] --> B[ARQ fragmentation and ACK]
B --> C[FEC data and parity]
C --> D[UDP]
D --> E[FEC recovery]
E --> F[ARQ ordering and reassembly]
F --> G[Complete message]Choose a Policy
| Policy | Setting | Use when |
|---|---|---|
| ARQ only, default | fec::options{} |
Loss is low and extra CPU/bandwidth matters |
| Fixed FEC | fec::options::fixed() |
Measured link characteristics justify predictable redundancy |
| Adaptive FEC | fec::options::adaptive() |
Link conditions vary and preset thresholds should adjust redundancy |
Choose by recovery latency, observed loss, message density and resource budgets. The same policies work for games, control messages and service communication. Sparse groups do not emit parity when they cannot meet the minimum useful group size.
#include <arknet/rudp/rudp_client.hpp>
#include <arknet/rudp/rudp_server.hpp>
arknet::rudp_server server;
arknet::rudp_client client;
auto settings = arknet::fec::options::adaptive();
settings.max_redundancy_percent = 50;
server.set_fec_options(settings);
client.set_fec_options(settings);Configure both endpoints while stopped. Fixed and adaptive senders interoperate:
each group carries its actual parameters. An FEC-enabled server also accepts an
ARQ-only client. Requesting FEC from an arknet server with FEC disabled fails with
operation_not_supported. An older server that ignores the new handshake causes
a connection timeout; the client does not silently downgrade.
Coding and Buffer Limits
| Parameter | Default | Behavior |
|---|---|---|
data_shards |
8 | Maximum data datagrams per group; range 1–32 |
parity_shards |
2 | Requested parity count for fixed policy |
max_parity_shards |
4 | Adaptive upper bound; range 1–16 |
min_data_shards |
2 | Smaller groups emit no parity |
group_wait_ms |
2 ms | Maximum grouping wait; ACK/window-control datagrams bypass grouping |
max_redundancy_percent |
50% | Per-group parity wire bytes divided by data wire bytes, including framing and padding |
group_lifetime_ms |
1000 ms | Retention deadline for incomplete receive groups |
max_groups |
128 | Maximum incomplete receive groups |
max_buffer_bytes |
1 MiB | Combined retention budget for pending send data and receive groups |
With 8 data and 2 parity shards, any 8 received shards reconstruct the data. This is a per-group count guarantee, not a guarantee for an arbitrary loss percentage. A burst removing more than 2 shards still needs ARQ. Byte budgets and the minimum group size can reduce the actual parity count below the configured value.
Complete groups release immediately; incomplete groups expire. When retention is full, valid systematic data still reaches ARQ while additional FEC buffering is skipped. Duplicate filtering has a fixed 4096-group window. Coding scratch space is bounded by shard count and MTU, separately from the retention budget.
arq::options::mtu remains the UDP payload limit. The handshake selects the smaller
endpoint value and deducts 26 bytes for FEC, so a 1200-byte wire MTU yields a
1174-byte ARQ datagram. Messages still have a 256-fragment limit. A larger configured
MTU does not prove path support; see buffer configuration.
Adaptive Thresholds
| Parameter | Default | Behavior |
|---|---|---|
sample_window_ms |
1000 ms | Window for retransmission samples and peer feedback |
min_samples |
64 | Keep parameters unchanged below this sample count |
enable_loss_percent |
3% | Increase parity at or above this threshold |
disable_loss_percent |
1% | Count healthy windows at or below this threshold |
stable_windows |
3 | Healthy windows before reducing parity by one shard |
cooldown_ms |
2000 ms | Minimum interval between ordinary adjustments |
overload_queue_percent |
75% | Disable parity at this queue occupancy, bypassing cooldown |
Adaptive mode starts with zero parity. It uses the larger observed local retransmission or peer missing-shard ratio, derives a parity count from that ratio, and applies both count and byte caps. RTT above twice the observed minimum with a growing queue also disables parity. ARQ congestion control remains active.
Read Statistics
// Wait outside endpoint callbacks while its IO context is still running.
auto pending = client.get_rudp_statistics();
auto stats = pending.get();
auto restored = stats.fec.recovered_shards;
auto retries = stats.retransmissions;
auto parity = stats.fec.current_parity_shards;
auto reason = arknet::fec::reason_name(stats.fec.last_change);Client and Session provide an asynchronous snapshot while connected; querying
an unconnected endpoint throws std::logic_error. Keep the IO context running;
shutdown can cancel a pending query. Reconnect starts a new statistics period.
last_change is configured, loss,
healthy or overload; policy_changes counts adjustments.
missing_shards counts originals absent when a group recovers or expires,
including recovered shards and possibly originals that arrive later.
recovered_shards counts originals reconstructed from parity.
retransmissions counts ARQ segment retransmissions. These units differ; their
difference is not a final-loss metric. Check application contents, order and completion.
Compatibility and Security
FEC uses version-1 negotiation and AFEC datagrams. ARQ-only retains the existing
KCP message-mode segments and ARK RDP control envelope. FEC requires compatible
arknet peers and cannot connect directly to bare KCP. CRC detects corruption;
it does not authenticate or encrypt a peer. Applications on untrusted networks
must provide identity verification and access control separately.
See configuration for admission/failure behavior and performance for measured scope.