# How DD Poker's Server-Client Communication Architecture Works: A Deep Dive into the Network Layer

> Explore DD Poker's server-client communication architecture. Discover its hybrid network stack combining TCP, HTTP, UDP reliability, and P2P sockets for efficient real-time gameplay.

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

---

**DD Poker implements a hybrid network stack that combines TCP/HTTP servlets for administrative traffic, a custom reliability layer over UDP for real-time game actions, and optional P2P sockets for direct peer connections.**

The open-source DD Poker codebase (`dougdonohoe/ddpoker`) demonstrates a sophisticated, multi-protocol approach to online gaming networking. This article examines the actual Java source to explain how the **server-client communication architecture** balances low-latency gameplay with robust administrative functionality.

## The Three-Layer Hybrid Architecture

DD Poker's network stack is divided into three distinct layers optimized for specific traffic types:

- **TCP/HTTP Servlet Layer**: Handles web UI, account management, and static resources through standard Java servlets.
- **UDP Game Transport**: A custom, connection-oriented UDP protocol for game actions, chat, and test connections.
- **P2P Overlay**: Optional direct client-to-client sockets for NAT traversal and private tables.

### TCP/HTTP Administrative Services

The server extends **`GameServer`** (located 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)), an abstract TCP server that creates `ServerSocketChannel` instances and routes HTTP requests to a `BaseServlet`. This layer manages the lobby interface, user accounts, and static resource delivery, leveraging standard servlet container robustness for non-time-critical operations.

### Custom UDP Transport Layer

For latency-critical gameplay, DD Poker implements a custom UDP stack centered around **`UDPServer`** ([`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)). This class runs a selector on one or more `DatagramChannel` instances and manages `UDPLink` objects representing individual client connections.

The **`PokerServer`** class ([`code/pokerserver/src/main/java/com/donohoedigital/games/poker/server/PokerServer.java`](https://github.com/dougdonohoe/ddpoker/blob/main/code/pokerserver/src/main/java/com/donohoedigital/games/poker/server/PokerServer.java)) implements both `UDPLinkHandler` and `UDPManagerMonitor` to receive game data and forward it to the engine. Similarly, **`ChatServer`** ([`code/pokerserver/src/main/java/com/donohoedigital/games/poker/server/ChatServer.java`](https://github.com/dougdonohoe/ddpoker/blob/main/code/pokerserver/src/main/java/com/donohoedigital/games/poker/server/ChatServer.java)) utilizes this same UDP infrastructure for chat traffic.

### Reliability Over UDP

Because UDP lacks built-in reliability, the architecture implements **`UDPLink`** and **`UDPManager`** (see [`UDPLink.java`](https://github.com/dougdonohoe/ddpoker/blob/main/UDPLink.java) and [`UDPManager.java`](https://github.com/dougdonohoe/ddpoker/blob/main/UDPManager.java)) to handle acknowledgments, retransmission logic, and timeout detection. This creates a connection-oriented abstraction over the connectionless UDP protocol.

### Optional P2P Sockets

For scenarios requiring direct client-to-client communication—such as private tables or NAT traversal—the codebase provides **`Peer2PeerClient`** ([`code/server/src/main/java/com/donohoedigital/p2p/Peer2PeerClient.java`](https://github.com/dougdonohoe/ddpoker/blob/main/code/server/src/main/java/com/donohoedigital/p2p/Peer2PeerClient.java)). This non-blocking `SocketChannel` wrapper manages DNS resolution and connection timeouts, while `Peer2PeerMessenger` handles status encoding and decoding.

## Client-Side Connection Initialization

The desktop client entry point, **`PokerMain`** ([`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)), initializes the network stack by creating a `UDPServer` in client mode, registering itself as a `UDPLinkHandler`, and launching the Swing UI.

When connecting to a server, the **`PokerConnect`** class ([`code/pokernetwork/src/main/java/com/donohoedigital/games/poker/network/PokerConnect.java`](https://github.com/dougdonohoe/ddpoker/blob/main/code/pokernetwork/src/main/java/com/donohoedigital/games/poker/network/PokerConnect.java)) orchestrates the handshake. It creates a `UDPLink`, packages an initial `OnlineMessage` containing license and version data into a `PokerUDPTransporter`, and blocks on a `WaitBoolean` until the server replies or times out.

```java
// Create the UDP manager (usually obtained from a UDPServer instance)
UDPServer udp = new UDPServer(myHandler, false);
udp.init();               // bind sockets, start selector thread
udp.start();

// Build the connect URL (host:port) and the initial OnlineMessage
PokerURL url = new PokerURL("poker.example.com", 7777);
OnlineMessage connectMsg = new OnlineMessage();
connectMsg.setWanAuth(authData);   // license / version info

// Perform the handshake
PokerConnect connector = new PokerConnect(udp, url, null /*listener*/);
boolean ok = connector.connect(connectMsg);
if (ok) {
    OnlineMessage reply = connector.getReply();
    // proceed – reply contains server‑assigned session info
}

```

## Server-Side Message Handling

The server processes incoming UDP packets through the `monitorEvent` method in `PokerServer`. When a packet arrives, the server validates the license key and version information, then constructs an `OnlineMessage` reply referencing the original message ID via `setInReplyTo`.

```java
public void monitorEvent(UDPLinkEvent event) {
    if (event.getType() == UDPLinkEvent.Type.RECEIVED) {
        UDPData data = event.getData();
        if (data.getType() == UDPData.Type.MESSAGE) {
            PokerUDPTransporter pkt = new PokerUDPTransporter(data);
            OnlineMessage msg = new OnlineMessage(pkt.getMessage());

            // Validate license, version, etc.
            EngineMessage validate = PokerServlet.validateKeyAndVersion(...);
            if (validate != null) {
                sendError(event.getLink(), validate.getApplicationErrorMessage());
                return;
            }

            // Build positive reply and queue it back
            OnlineMessage reply = new OnlineMessage();
            reply.setInReplyTo(msg.getMessageID());
            reply.setData(new DDMessage(...));
            event.getLink().queue(new PokerUDPTransporter(reply.getData()).getData());
            event.getLink().send();
        }
    }
}

```

## Peer-to-Peer Connection Setup

For direct peer connections, clients instantiate `Peer2PeerClient` using a `P2PURL`. The connection is non-blocking and includes timeout handling through a dedicated selector thread.

```java
P2PURL p2pUrl = new P2PURL("peer.example.com", 8888);
Peer2PeerClient p2p = new Peer2PeerClient(p2pUrl, msgListener, connListener);
p2p.connect();                     // non‑blocking connect with timeout handling
// After connection:
msgListener.updateStep(DDMessageListener.STEP_CONNECTED);

```

## Complete Communication Flow

The lifecycle of a DD Poker network session follows these sequential steps:

1. **Client Startup**: `PokerMain` initializes a client-mode `UDPServer` and registers as a `UDPLinkHandler` and `UDPManagerMonitor`.
2. **Handshake Initiation**: `PokerConnect.connect(OnlineMessage)` obtains a `UDPLink` from the local `UDPManager`, attaches a monitor, and transmits the initial authentication message.
3. **Server Validation**: `PokerServer` receives the packet via `monitorEvent`, validates credentials through `PokerServlet.validateKeyAndVersion()`, and queues a reply to the originating `UDPLink`.
4. **Client Acknowledgment**: `PokerConnect` receives the reply, verifies the `inReplyTo` field matches the original request, and unblocks the waiting thread. If the status is OK, the client enters the lobby.
5. **Game Messaging**: Post-handshake, both entities exchange game-specific messages (bets, folds, chat) over the established `UDPLink`. The server forwards these to the `EngineServer`, while the client routes them to the UI through `p2pMessageReceived`.
6. **Direct Peer Exchange**: For private tables, clients activate `Peer2PeerClient` to establish direct sockets, bypassing the central server for specific data streams.

## Summary

- DD Poker employs a **hybrid architecture** combining HTTP servlets, custom UDP transports, and optional P2P sockets.
- **TCP/HTTP** layers in `GameServer` handle administrative traffic, while **UDP** layers in `UDPServer` manage real-time gameplay.
- The **UDP reliability layer** (`UDPLink`, `UDPManager`) implements acknowledgments and retransmissions over connectionless UDP.
- **Client connections** are initiated via `PokerConnect`, which blocks until the server replies or times out.
- **Server processing** occurs in `PokerServer`, which implements `UDPLinkHandler` to validate clients and route game data.
- **Optional P2P** functionality via `Peer2PeerClient` enables direct client-to-client communication for NAT traversal scenarios.

## Frequently Asked Questions

### Why does DD Poker use UDP instead of TCP for game traffic?

UDP provides lower latency for real-time poker actions, avoiding TCP's head-of-line blocking and congestion control delays. According to the source code in [`UDPLink.java`](https://github.com/dougdonohoe/ddpoker/blob/main/UDPLink.java) and [`UDPManager.java`](https://github.com/dougdonohoe/ddpoker/blob/main/UDPManager.java), the implementation handles packet loss through custom acknowledgment and retransmission logic while maintaining UDP's speed advantages.

### How does the server validate incoming client connections?

The server validates connections in the `PokerServer.monitorEvent()` method by inspecting the `OnlineMessage` payload. It calls `PokerServlet.validateKeyAndVersion()` to verify license keys and client versions before sending an acknowledgment reply via the `UDPLink.queue()` and `send()` methods.

### What is the purpose of the Peer2PeerClient in the architecture?

`Peer2PeerClient` enables direct socket connections between clients, bypassing the central server for certain features like private tables or NAT traversal scenarios. It wraps non-blocking `SocketChannel` objects and handles DNS resolution with timeout awareness, as implemented in [`Peer2PeerClient.java`](https://github.com/dougdonohoe/ddpoker/blob/main/Peer2PeerClient.java).

### How does the client handle connection timeouts during the initial handshake?

The `PokerConnect` class implements a blocking handshake mechanism using a `WaitBoolean`. When calling `connect(OnlineMessage)`, the client queues the transport packet and blocks until the server's reply triggers `monitorEvent`, which sets the boolean and unblocks the waiting thread. If no reply arrives within the configured timeout, the connection attempt fails gracefully.