Packet Protocol
Purpose
Understanding the binary packet format used by the RCON protocol for communication between client and server.
Overview
RCON uses a simple binary packet format with four fields: size, ID, type, and payload. All packets follow this structure regardless of direction (client-to-server or server-to-client).
Packet Structure
| Field | Size | Type | Description |
|---|---|---|---|
Size | 4 bytes | int32 (little-endian) | Length of ID, Type, and Payload fields combined |
ID | 4 bytes | int32 (little-endian) | Request/response identifier for matching |
Type | 4 bytes | int32 (little-endian) | Packet type (see Packet Types) |
Payload | Variable | byte array | Actual data, null-terminated with |
+-----------+-----------+-----------+-----------+
| Size (4) | ID (4) | Type (4) | Payload |
+-----------+-----------+-----------+-----------+
| Little-endian integers | Variable |
+-----------+-----------+-----------+-----------+Packet Types
| Value | Constant | Description |
|---|---|---|
0 |
| Authentication response from server |
2 |
| Command response from server |
3 |
| Authentication request from client |
Size Field Calculation
The Size field contains the length of everything after itself:
int size = 4 (ID) + 4 (Type) + payload.length + 1 (null terminator);For example, a password "secret" would have: - Payload: 6 bytes (s, e, c, r, e, t) - Null terminator: 1 byte - ID: 4 bytes - Type: 4 bytes - Size = 4 + 4 + 6 + 1 = 15
ID Field
The ID field matches requests with responses:
-
Client-to-server: Any positive integer (typically auto-incrementing)
-
Server-to-client: Matches the request ID, or
0for authentication responses
// Client generates unique ID
int requestId = requestCounter.getAndIncrement();
// Server responds with same ID
// All response packets for this request use the same IDPayload Encoding
Null Termination
All payloads must end with a \0 (null) byte:
byte[] payload = command.getBytes(charset);
byte[] terminatedPayload = new byte[payload.length + 1];
System.arraycopy(payload, 0, terminatedPayload, 0, payload.length);
// terminatedPayload[payload.length] is already 0Example Packets
Authentication Request
Size: 12
ID: 1
Type: 3
Payload: "secret\0"
Hex (little-endian):
0C 00 00 00 // Size = 12
01 00 00 00 // ID = 1
03 00 00 00 // Type = 3 (AUTH)
73 65 63 72 65 74 00 // "secret\0"Command Request
Size: 15
ID: 2
Type: 3
Payload: "list\0"
Hex (little-endian):
0F 00 00 00 // Size = 15
02 00 00 00 // ID = 2
03 00 00 00 // Type = 3 (AUTH)
6C 69 73 74 00 // "list\0"Size Limits
| Direction | Limit | Notes |
|---|---|---|
Client → Server | 1460 bytes total | Typical MTU, includes headers |
Server → Client | 4104 bytes total | 4096 bytes payload + headers |
Responses exceeding 4096 bytes are split across multiple packets. See Fragment Resolution for details.
Byte Order
Critical: All integer fields use little-endian byte order, opposite of Java’s default big-endian.
// WRONG - uses big-endian
byte[] bytes = ByteBuffer.allocate(4).putInt(value).array();
// CORRECT - uses little-endian
byte[] bytes = ByteBuffer.allocate(4)
.order(ByteOrder.LITTLE_ENDIAN)
.putInt(value)
.array();See Byte Order for more details.
See Also
-
Fragment Resolution - Multi-packet responses
-
Byte Order - Little-endian encoding details
-
Charset Handling - Text encoding options
-
Protocol Specification - Complete protocol docs