jinzhongjia/zig-kcp
KCP - A Fast and Reliable ARQ Protocol (Zig Implementation)
English | 简体中文
A Zig implementation of the KCP protocol, based on the original C implementation by skywind3000.
KCP is a fast and reliable ARQ (Automatic Repeat reQuest) protocol that offers significant advantages over TCP:
# Clone the repository
git clone https://github.com/yourusername/zig-kcp.git
cd zig-kcp
# Run tests
zig build test
# Run benchmarks
zig build bench
const std = @import("std");
const kcp = @import("kcp");
// 1. Define output callback function (for sending underlying packets)
fn outputCallback(buf: []const u8, k: *kcp.Kcp, user: ?*anyopaque) !i32 {
// Send data via UDP socket
// This is just an example
return @as(i32, @intCast(buf.len));
}
pub fn main() !void {
const allocator = std.heap.page_allocator;
// 2. Create KCP instance
const conv: u32 = 0x12345678; // Conversation ID, must be same for both peers
const kcp_inst = try kcp.create(allocator, conv, null);
defer kcp.release(kcp_inst);
// 3. Set output callback
kcp.setOutput(kcp_inst, &outputCallback);
// 4. Configure KCP (optional)
// Parameters: nodelay, interval, resend, nc
// Normal mode: setNodelay(0, 40, 0, 0)
// Fast mode: setNodelay(1, 10, 2, 1)
kcp.setNodelay(kcp_inst, 1, 10, 2, 1);
// 5. Send data
const message = "Hello, KCP!";
_ = try kcp.send(kcp_inst, message);
// 6. Update periodically (e.g., every 10ms)
const current = @as(u32, @intCast(std.time.milliTimestamp()));
try kcp.update(kcp_inst, current);
// 7. Call input when receiving underlying packets
// const data = ...; // Data received from UDP socket
// _ = try kcp.input(kcp_inst, data);
// 8. Read received data
var buffer: [1024]u8 = undefined;
const len = try kcp.recv(kcp_inst, &buffer);
if (len > 0) {
std.debug.print("Received: {s}\n", .{buffer[0..@as(usize, @intCast(len))]});
}
}
create(allocator, conv, user)Create a KCP instance
allocator: Memory allocatorconv: Conversation ID, must be the same for both communicating peersuser: User-defined data pointer (optional)release(kcp)Release the KCP instance and its resources
setOutput(kcp, callback)Set the output callback function, which KCP uses to send underlying packets
fn callback(buf: []const u8, kcp: *Kcp, user: ?*anyopaque) !i32
setNodelay(kcp, nodelay, interval, resend, nc)Configure KCP working mode
nodelay: 0=disabled (default), 1=enabledinterval: Internal update interval (milliseconds), default 100msresend: Fast retransmission trigger count, 0=disabled (default)nc: 0=normal congestion control (default), 1=disable congestion controlRecommended configurations:
setNodelay(0, 40, 0, 0)setNodelay(1, 20, 2, 1)setNodelay(1, 10, 2, 1)setMtu(kcp, mtu)Set MTU size, default 1400 bytes
wndsize(kcp, sndwnd, rcvwnd)Set send and receive window sizes
sndwnd: Send window, default 32rcvwnd: Receive window, default 128send(kcp, buffer)Send data
recv(kcp, buffer)Receive data
-1: Receive queue is empty-2: Incomplete packet-3: Buffer too smallinput(kcp, data)Input underlying packet data into KCP (e.g., data received from UDP)
update(kcp, current)Update KCP state, should be called periodically (recommended: 10-100ms)
current: Current timestamp (milliseconds)check(kcp, current)Check when to call update next
flush(kcp)Immediately flush pending data
peeksize(kcp)Get the size of the next message in the receive queue
waitsnd(kcp)Get the number of packets waiting to be sent
getconv(data)Extract conversation ID from a packet
# Run unit tests
zig build test
# Run performance benchmarks (fast, suitable for CI)
zig build bench
# Run integration tests with network simulation (slow, for manual testing)
zig build perf
# View detailed test output
zig build test --summary all
KCP is an ARQ (Automatic Repeat reQuest) protocol operating at the application layer, designed to work with unreliable transport protocols like UDP.
Sender:
send() to queue dataupdate() to trigger KCP processingReceiver:
input() when receiving packets from UDPrecv() to read reassembled dataTimer:
update() to handle retransmissions, ACKs, etc.0 4 5 6 8 12 16 20 24
+---------------+-------+-------+-------+-------+-------+-------+-------+
| conv | cmd | frg | wnd | ts | sn | una | len |
+---------------+-------+-------+-------+-------+-------+-------+-------+
conv: Conversation ID (4 bytes)cmd: Command type (1 byte): PUSH, ACK, WASK, WINSfrg: Fragment number (1 byte)wnd: Window size (2 bytes)ts: Timestamp (4 bytes)sn: Sequence number (4 bytes)una: Unacknowledged sequence number (4 bytes)len: Data length (4 bytes)Reduce latency:
setNodelay(1, 10, 2, 1) configurationinterval parameterIncrease throughput:
Reduce CPU usage:
interval parameter appropriatelycheck() to optimize update() call frequency| Category | Count | Coverage |
|---|---|---|
| Basic Functions | 9 | Encode/decode, utilities, create/release |
| Configuration | 6 | MTU, window, nodelay, stream mode |
| Error Handling | 5 | Invalid conv, corrupted data, buffer issues |
| ARQ Mechanisms | 5 | Timeout retransmission, fast retransmission |
| Fragmentation | 2 | Large data, multi-fragment reassembly |
| Advanced Features | 3 | Window probe, flush, window full |
| Fuzz Testing | 3 | Random input, malformed packets, edge values |
| Stress Testing | 3 | Many small packets, large data, bidirectional |
| Boundary Testing | 8 | MTU, window, sequence wraparound |
| Dead Link | 2 | Complete loss, gradual retransmission |
| Receive Window | 3 | Window full, flow control, zero window |
| RTT Testing | 2 | RTT calculation, delay variation |
| Congestion Control | 2 | ssthresh adjustment, slow start |
| Timestamp | 2 | Wraparound, time jump |
| Interval | 3 | Update frequency, flush timing |
| Nodelay Modes | 3 | Normal, fast, comparison |
Memory Management:
Data Structures:
ArrayList instead of C linked listsType Safety:
Error Handling:
Modularity:
This implementation is based on the original KCP protocol by skywind3000.