TcpOverUdpServer
TcpOverUdpServer is the server-side peer of TcpOverUdpClient. It receives packet-preserving KCP datagrams from the
previous node, reconstructs the original byte stream, and forwards that stream to the next node. Replies from the next
node are encoded back into KCP datagrams and sent downstream toward the previous packet side.
It is normally paired with TcpOverUdpClient on the remote side.
Typical placement
Server side:
UdpListener -> TcpOverUdpServer -> TcpConnector
UdpListener -> TcpOverUdpServer -> MuxServer -> TcpConnector
Matching client side:
TcpListener -> TcpOverUdpClient -> UdpConnector
TcpListener -> MuxClient -> TcpOverUdpClient -> UdpConnector
The previous side of TcpOverUdpServer must preserve datagram boundaries. The next side is stream-facing.
Basic example
{
"name": "tcp-over-udp-server",
"type": "TcpOverUdpServer",
"settings": {
"fec": false,
"kcp-send-window": 8192,
"kcp-recv-window": 8192,
"ping-interval-ms": 10000,
"no-recv-timeout-ms": 30000
},
"next": "service-out"
}
Matching service connector:
{
"name": "service-out",
"type": "TcpConnector",
"settings": {
"address": "127.0.0.1",
"port": 8080
}
}
FEC example
{
"name": "tcp-over-udp-server",
"type": "TcpOverUdpServer",
"settings": {
"fec": true,
"fec-data-shards": 10,
"fec-parity-shards": 3
},
"next": "service-out"
}
FEC settings must match the TcpOverUdpClient side exactly.
Required fields
settings is optional. If it is absent or not an object, defaults are used.
next is required in normal use. It should point to the stream-side service path that receives reconstructed payload.
Optional settings
TcpOverUdpServer uses the same setting names and defaults as TcpOverUdpClient.
| Field | Default | Validation | Description |
|---|---|---|---|
fec | false | boolean | Enables Reed-Solomon forward error correction around KCP datagrams. |
fec-data-shards | 10 | positive, with total shards less than or equal to 255 | Number of data shards per FEC block. Used only when fec is enabled. |
fec-parity-shards | 3 | positive, with total shards less than or equal to 255 | Number of parity shards per FEC block. Used only when fec is enabled. |
kcp-nodelay | true | boolean | Enables KCP nodelay mode. |
kcp-interval-ms | 10 | 10..5000 | KCP update interval. |
kcp-resend | 2 | >= 0 | KCP fast-resend threshold. |
kcp-no-congestion-control | true | boolean | Disables KCP congestion control. |
kcp-send-window | 8192 | >= 1 | KCP send window in segments. |
kcp-recv-window | 8192 | >= 1 | KCP receive window in segments. |
kcp-initial-cwnd | half of kcp-send-window | 1..kcp-send-window | Initial KCP congestion window. |
kcp-rx-minrto-ms | 30 | >= 1 | Minimum KCP retransmission timeout. |
kcp-send-buffer-limit | 0 | >= 0 | Backpressure threshold. 0 derives the limit from local send window + remote window + 10. |
ping-interval-ms | 10000 | >= 1 | Idle receive interval before sending an internal ping frame. |
no-recv-timeout-ms | 30000 | greater than ping-interval-ms | Idle receive interval before closing the line. |
KCP transport model
On upstream Init, the server initializes per-line state, creates a KCP session, starts the KCP timer loop, creates FEC
state if enabled, queues an initial internal ping frame, and forwards upstream Init to the next stream-side node.
When packet payload arrives from the previous node:
- FEC decoding is applied if enabled.
- KCP receives the datagram.
- Completed KCP payloads are drained.
- The one-byte internal frame flag is removed.
- Data frames are forwarded upstream to the next node as reconstructed stream payload.
When stream payload comes back from the next node:
- The payload is split into chunks no larger than the effective KCP write MTU.
- Each chunk is prefixed with the one-byte data flag.
- The framed chunk is sent through KCP.
- KCP output datagrams are forwarded downstream to the previous packet side.
Internal frame flags
Inside the KCP payload, TcpOverUdpServer uses the same one-byte frame flags as the client:
| Flag | Meaning |
|---|---|
0x00 | Data frame. Bytes after the flag are real stream payload. |
0xF0 | Ping frame. Used as an internal keepalive marker. |
0xFF | Close frame. Requests shutdown of the paired line. |
Empty data frames are discarded.
MTU and padding
The KCP MTU is based on GLOBAL_MTU_SIZE. With FEC enabled, 8 bytes of FEC outer header are subtracted from the KCP MTU
and from the stream write budget.
The effective stream write payload budget is:
GLOBAL_MTU_SIZE - 20 - 8 - 24 - 1 - fec_overhead
The node advertises required_padding_left = 1 so it can prepend the internal frame flag before handing data to KCP.
FEC behavior
With fec: true, outbound KCP datagrams are wrapped in Reed-Solomon FEC packets. Data shards are emitted immediately,
and parity shards are emitted after each configured data-shard block.
On receive, the decoder:
- accepts FEC-wrapped KCP datagrams
- feeds valid data shards into KCP
- tries to recover missing KCP datagrams from parity shards
- drops invalid FEC packets conservatively
FEC is symmetric. Enable it and configure the same shard counts on both peers.
Backpressure
If KCP queued send data grows beyond kcp-send-buffer-limit, the server schedules an upstream Pause toward the next
stream side. When KCP output drains below the threshold, the KCP output callback schedules upstream Resume.
This prevents unbounded queue growth when the UDP packet side cannot drain quickly enough.
Close and timeout behavior
If the next stream-facing side finishes, TcpOverUdpServer:
- marks upstream as closed so re-entrant callbacks are not reflected back toward the finished side
- sends an internal close frame through KCP
- flushes KCP output
- destroys local line state
- forwards downstream
Finishto the packet side
If a close frame is received from the remote peer, the server destroys local state, finishes the stream side, and then finishes the packet side if the line is still alive.
If no receive activity happens for ping-interval-ms, a ping frame is sent. If receive inactivity exceeds
no-recv-timeout-ms, the line is closed.
Node metadata
| Property | Value |
|---|---|
| Node flag | kNodeFlagNone |
| Previous node | Allowed |
| Next node | Allowed, required in normal use |
| Layer group | kNodeLayerAnything |
required_padding_left | 1 |
Common mistakes
- Do not feed
TcpOverUdpServerfrom a stream-only previous node. The previous side must preserve packet boundaries. - Do not forget the matching
TcpOverUdpClient. - Do not enable FEC on only one side.
- Do not use mismatched FEC shard counts.
- Do not expect
TcpOverUdpServerto be a chain end; it forwards reconstructed stream payload tonext.