# How DD Poker Handles Network Communication: UDP vs TCP Protocols

> Discover how DD Poker utilizes UDP and TCP protocols for game network communication. Learn about their custom reliability layer for low-latency traffic and connection-oriented services.

- Repository: [Doug Donohoe/ddpoker](https://github.com/dougdonohoe/ddpoker)
- Tags: deep-dive
- Published: 2026-02-28

---

**DD Poker maintains two independent networking stacks—TCP for reliable, connection-oriented services like lobby management and file transfers, and UDP with a custom reliability layer for low-latency game traffic and real-time chat.**

The open-source DD Poker application (`dougdonohoe/ddpoker`) implements a dual-protocol architecture to optimize for different network requirements. By handling UDP versus TCP protocols through completely separate code paths, the application minimizes latency for real-time gameplay while ensuring data integrity for administrative functions. Both stacks share common configuration patterns and logging infrastructure but implement distinct life-cycle management, threading models, and reliability mechanisms.

## TCP Stack Architecture

The TCP implementation provides guaranteed, ordered delivery for operations requiring data integrity over speed.

### Server Initialization and Binding

The `GameServer` class in [`code/server/src/main/java/com/donohoedigital/server/GameServer.java`](https://github.com/dougdonohoe/ddpoker/blob/main/code/server/src/main/java/com/donohoedigital/server/GameServer.java) initializes the TCP listener. The `_init()` method opens one or more `ServerSocketChannel`s, binds them to ports defined in `settings.tcp.*` entries (typically from `code/pokerserver/src/main/resources/config/poker/server.properties`), and registers them with a `Selector` for non-blocking I/O operations.

A single selector thread runs the accept loop, while a `ThreadPool` handles the actual game logic for each connection. The server uses `Utils.getLocalAddressPort(ServerSocketChannel)` from [`code/common/src/main/java/com/donohoedigital/base/Utils.java`](https://github.com/dougdonohoe/ddpoker/blob/main/code/common/src/main/java/com/donohoedigital/base/Utils.java) for diagnostic logging of bound addresses.

### Connection Handling

Per-connection management occurs in `PokerTCPServer` (extending `Peer2PeerServer`). When a client connects, the server accepts the `SocketChannel`, creates a `PokerConnection`, and passes `Peer2PeerMessage` objects to the game engine. Sending data requires no additional framing logic—messages write directly to the channel via `PokerTCPServer.write()`.

```java
// In PokerMain – force TCP usage for lobby or file transfer
PokerConnectionServer tcpSrv = getPokerConnectionServer(false);
// tcpSrv is an instance of PokerTCPServer (extends Peer2PeerServer)

```

### Built-in Reliability

TCP guarantees in-order delivery, retransmission, and flow control at the transport layer. DD Poker leverages these native features without implementing additional acknowledgment logic. The `Peer2PeerMessage.read()` and `Peer2PeerMessage.write()` methods interact directly with the `SocketChannel` stream.

## UDP Stack and Custom Reliability

The UDP implementation prioritizes speed for latency-sensitive operations, implementing its own reliability mechanisms on top of the connectionless protocol.

### Datagram Channel Management

The `UDPServer` class in [`code/udp/src/main/java/com/donohoedigital/udp/UDPServer.java`](https://github.com/dougdonohoe/ddpoker/blob/main/code/udp/src/main/java/com/donohoedigital/udp/UDPServer.java) creates `DatagramChannel`s bound to ports specified by `settings.udp.port` and `settings.udp.chat.port` in `code/poker/src/main/resources/config/poker/client.properties`. The `_init()` method configures non-blocking channels registered with a `Selector`, reading raw datagrams into reusable `ByteBuffer` instances.

Diagnostic helpers in [`Utils.java`](https://github.com/dougdonohoe/ddpoker/blob/main/Utils.java) provide `getLocalAddressPort(DatagramChannel)` for logging UDP endpoint information, mirroring the TCP utility functions.

### Application-Level Reliability

Since UDP provides no delivery guarantees, `UDPManager` in [`code/udp/src/main/java/com/donohoedigital/udp/UDPManager.java`](https://github.com/dougdonohoe/ddpoker/blob/main/code/udp/src/main/java/com/donohoedigital/udp/UDPManager.java) implements a custom reliability layer:

- **Acknowledgment Tracking**: Every data packet pairs with `PING_ACK` or `MTU_ACK` responses. The manager periodically executes `processSendAcksPing()` to transmit ACK bursts and `processSendAll()` to retransmit unacknowledged packets.
- **Link State Management**: `UDPLink` maintains lists of unacked `UDPData` chunks with exponential back-off timing. The `requiresExistingLink()` method validates session continuity via `sessionID_` fields in `UDPMessage` headers.
- **Health Monitoring**: Stale peers trigger timeouts, and `UDPLinkHandler` callbacks notify the application of connection state changes.

```java
// Inside UDPManager.run() – reliability loop
if (msg == SENDACK) processSendAcksPing();   // periodic ACK burst
else if (msg == SENDALL) processSendAll();   // retransmit pending packets

```

### Threading and Dispatch

The UDP architecture uses a three-thread model:
1. **Server Thread**: `UDPServer` reads datagrams from the kernel and queues `UDPMessage` objects.
2. **Manager Thread**: `UDPManager` processes the `LinkedBlockingQueue`, handles retransmission timers, and invokes `UDPLinkHandler` callbacks.
3. **Timer Tasks**: Periodic tasks drive the ACK and retransmission cycles.

## Protocol Selection Logic

The `PokerMain` class in [`code/poker/src/main/java/com/donohoedigital/games/poker/PokerMain.java`](https://github.com/dougdonohoe/ddpoker/blob/main/code/poker/src/main/java/com/donohoedigital/games/poker/PokerMain.java) serves as the decision point for network communication protocol selection. The `getPokerConnectionServer(boolean bUDP)` method returns a UDP server when the flag is true (default for game traffic) and a TCP server otherwise.

```java
// Snippet from PokerMain – selecting server type
if (bUDP) {
    p2p_ = getCreateUDPServer();   // UDP path for game traffic
} else {
    p2p_ = getTCPServer();         // TCP path for lobby/file transfer
}

```

**Chat Services**: Always use UDP via `getChatServer()`, which returns a `PokerUDPServer`, prioritizing low latency over guaranteed delivery for text messages.

**LAN Discovery**: Uses a separate multicast UDP listener (`LanManager`) that operates independently of both primary stacks.

## Message Transmission Patterns

### Sending over TCP

TCP message transmission operates through direct channel writes:

```java
Peer2PeerMessage p2p = new Peer2PeerMessage(Peer2PeerMessage.P2P_MSG, myDDMessage);
int bytesSent = tcpSrv.send(p2pConnection, p2p);   // PokerTCPServer.write()

```

The `PokerTCPServer.send()` method writes directly to the `SocketChannel` without additional buffering or framing beyond the `Peer2PeerMessage` serialization.

### Sending over UDP

UDP transmission delegates to the manager's work queue:

```java
// Build a UDPMessage and hand it to the manager
udpSrv.manager().addMessage(myUDPMessage);

```

`UDPManager.addMessage()` places the message on its internal queue. The manager thread later serializes the `UDPMessage` (encoding headers and `UDPData` chunks) and transmits via `DatagramChannel`, handling retransmission automatically if acknowledgments fail to arrive within the back-off window.

## Configuration and Port Management

Both stacks utilize property-driven configuration but use distinct key patterns:

- **TCP Ports**: Defined by generic `settings.tcp.*` entries in `code/pokerserver/src/main/resources/config/poker/server.properties`
- **UDP Ports**: Explicitly defined by `settings.udp.port` and `settings.udp.chat.port` in `code/poker/src/main/resources/config/poker/client.properties`

The `Utils` class provides socket diagnostic helpers for both protocols, enabling consistent logging of local addresses and ports regardless of transport type.

## Summary

- **DD Poker implements separate TCP and UDP stacks** to optimize for reliability versus latency requirements.
- **TCP handles lobby services and file transfers** using standard `ServerSocketChannel` and `SocketChannel` APIs with built-in transport reliability.
- **UDP manages real-time game traffic and chat** through `DatagramChannel` with a custom acknowledgment and retransmission layer in `UDPManager`.
- **Protocol selection occurs in `PokerMain.getPokerConnectionServer()`**, which instantiates `PokerTCPServer` or `PokerUDPServer` based on the `bUDP` parameter.
- **Configuration uses distinct property keys** (`settings.tcp.*` versus `settings.udp.port`) across server and client property files.

## Frequently Asked Questions

### Why does DD Poker use both UDP and TCP instead of just one protocol?

DD Poker uses TCP for operations requiring guaranteed delivery like file transfers and lobby management, where latency matters less than data integrity. For real-time game traffic and chat, UDP minimizes latency and jitter, while the custom `UDPManager` reliability layer handles packet loss through application-level acknowledgments rather than TCP's head-of-line blocking.

### How does DD Poker ensure reliable delivery over UDP?

The `UDPManager` class implements exponential back-off retransmission, pairing every data packet with `PING_ACK` or `MTU_ACK` responses via `processSendAcksPing()` and `processSendAll()` methods. `UDPLink` tracks unacknowledged `UDPData` chunks and session IDs, removing stale peers when timeouts exceed configured thresholds.

### What determines whether a connection uses UDP or TCP in DD Poker?

The `PokerMain.getPokerConnectionServer(boolean bUDP)` method acts as the selection logic. When `bUDP` is true (the default for active gameplay), the system calls `getCreateUDPServer()` to instantiate `PokerUDPServer`; when false, it calls `getTCPServer()` for `PokerTCPServer`. Chat services explicitly use UDP through `getChatServer()`, while LAN discovery uses a separate multicast UDP listener.

### How are ports configured for each protocol in DD Poker?

TCP ports are read from generic `settings.tcp.*` entries in `code/pokerserver/src/main/resources/config/poker/server.properties`, while UDP ports use explicit keys `settings.udp.port` and `settings.udp.chat.port` defined in `code/poker/src/main/resources/config/poker/client.properties`. Both protocols use `Utils.getLocalAddressPort()` for diagnostic logging of bound channels.