The server’s network layer is built directly on Windows I/O Completion Ports (IOCP), the highest-throughput async I/O model available on Win32. Rather than one thread per connection, IOCP posts completed I/O events—accepts, receives, sends, disconnects, and timer firings—onto a shared kernel queue. A fixed pool ofDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/kenzz55/ue5-iocp-mmo-server/llms.txt
Use this file to discover all available pages before exploring further.
WORKER_THREAD_COUNT = 4 worker threads calls GetQueuedCompletionStatus in a tight loop, pulling completions off that queue and dispatching them by their IoType. This design scales to thousands of concurrent TCP sessions without thread explosion and keeps latency predictable under load.
IoType Enum
Every asynchronous I/O operation the server posts is represented by anIoContext structure. The IoType field on that context tells the worker thread what kind of completion arrived.
IoType | Meaning |
|---|---|
Accept | AcceptEx fired; HandleAcceptCompletion extracts the remote address and registers the session |
Recv | TCP bytes arrived; ProcessRecvData assembles packets from the ring buffer and dispatches them |
Send | Outbound TCP data was consumed; TryPostNextSend chains the next queued send if one exists |
Disconnect | DisconnectEx with TF_REUSE_SOCKET completed; socket is clean and session returns to pool |
UdpRecv | UDP datagram arrived; HandleUdpRecvCompletion routes it to HandleUdpPacket |
UdpSend | UDP datagram was sent; the IoContext is returned to the UDP send-context pool |
Timer | TimerManager posts a zero-byte completion to wake a worker for a scheduled callback |
TCP Transport
TCP carries all reliable packets—game entry, chat, combat acknowledgements, and inventory operations. Accept flow:IOCPServer::Run()callsCreateIoCompletionPortto create the IOCP handle, then associates the listen socket with it.PrePostAcceptspre-postsInitialSessionPoolSize = 1024AcceptExcalls, each backed by a pre-allocatedSessionfromSessionPool.- When a connection arrives, the completion appears with
IoType::Accept.HandleAcceptCompletioncallsGetAcceptExSockAddrsto extract the remote address, transitions the session toConnected, and immediately posts a freshAcceptExto keep the accept pipeline full.
| Parameter | Value | Purpose |
|---|---|---|
RecvBufferSize | 131,072 B | Per-session PacketBuffer ring capacity |
SendBufferSize | 65,536 B | Per-session outbound scatter-gather send queue capacity |
InitialSessionPoolSize | 1,024 | Pre-allocated Session objects at startup |
WORKER_THREAD_COUNT | 4 | Threads calling GetQueuedCompletionStatus |
MaxPacketSize | 16,384 B | Maximum accepted incoming packet size |
UDP Transport
A separate UDP socket is bound to the same port 7777 as the TCP listen socket. It is used exclusively for movement replication because movement inputs arrive at high frequency (up to one per client render frame) and can tolerate occasional loss.PrePostUdpReceives posts multiple WSARecvFrom calls at startup, each with IoType::UdpRecv. On completion, HandleUdpRecvCompletion identifies the session by UDP endpoint key (address + port) and routes movement inputs into the game simulation command queue. Outbound UDP datagrams use a pool of IoContext objects acquired via AcquireUdpSendContext and released in the UdpSend completion path.
Worker Thread Loop
All four worker threads run identical loops. Pseudocode drawn fromIOCPServer::WorkerThread():
IoContext structs are never heap-allocated per operation. Each Session owns three persistent contexts—recvContext_, sendContext_, and disconnectContext_—that are reused across the lifetime of the connection. UDP send contexts come from a separate IoContext pool managed by AcquireUdpSendContext / ReleaseUdpSendContext. This eliminates per-I/O allocation pressure on hot paths.Port Layout
IoType field always distinguishes them.