Table of Contents
Why Games Prefer UDP?
How come networked games rely almost exclusively on the UDP protocol to exchange data packets? And what are the drawbacks of WebSocket?
This article explains the alternatives and some details about IP networking and how it affects Unity Netcode games.
Why Aren’t We Gaming With TCP?
There are several reasons for choosing UDP over the TCP protocol.
Reliable Transfer, Retransmission
TCP packets are sent reliably. To achieve this, additional acknowledgement (ACK) packets are sent back to the sender.
If a packet is determined to be lost along the route, even if it’s not important, it gets re-requested and re-sent. This happens with a delay because the sender has to assume that a packet got lost when the ACK packet didn’t arrive in a given time.
3x Larger Packet Header Size
The TCP packet header has a minimum size of 20 bytes, up to a max of 60 bytes. These days a TCP header is commonly 32 bytes but can be higher for individual packets.
On average that makes the TCP header 4 times larger than UDP’s fixed-size header of 8 bytes.
You might think this is negligible, but when you’re sending dozens of packets per frame at a rate of 30 Hz the additional TCP header size (24 bytes) alone can account for 10-100 KiB/s of the total traffic.
Connection Handshake
TCP is a connection-based protocol. Both endpoints first have to agree on establishing the connection and setting transfer parameters.
This means both parties first exchange several handshake packets, and may need to re-connect at a later time.
Although UDP networking APIs likely implement their own form of handshaking as well.
What About WebSocket?
To understand why WebSocket is never the preferred choice unless you have to do networking in a web application, you only need to know that WebSocket is using the TCP protocol.
Web applications simply cannot make use of the UDP protocol.
Web Apps Cannot Host Game Sessions
Web browsers impose another severe restriction: they don’t allow a web application to listen for incoming connections.
A web application therefore cannot host a network game session and generally cannot act as a server process. There is no way around that limitation.
Cross-Platform Play With Web Clients
In order to allow web clients to connect to a dedicated server, the server needs to run with WebSockets enabled.
If you also want to have non-web clients join the same server, they too need to connect via WebSockets since you cannot connect to the same server with both UDP and TCP simultaneously.
Thus cross-platform games where web clients are supposed to be able to join the same server are hampered by the limitations imposed by WebSocket / TCP.
The Unity Transport documentation provides some more details.
IP Packet Fragmentation
Any IP packet (on which TCP/UDP sit atop) sent across the Internet may get fragmented along the way into several individual packets, each with their own header.
Fragmentation occurs when the packet is too large to be sent in hole between two routers (hops) along the route. How much is too large is a setting that each two hops agree on.
Fragmentation Leads To Higher Latency
Since the TCP protocol header is larger than a UDP protocol header, TCP packets have a slightly higher chance of getting fragmented.
Packet fragmentation adds a latency penalty, because what was once a single packet now needs to wait for several fragmented packets to arrive at the same hop before the original packet can be put back together and sent out to the next hop.
Maximum Transmission Unit (MTU)
The guaranteed unfragmented IPv4 packet size is 576 bytes. For IPv6 it’s 1,280 bytes. Higher values are determined by the MTU setting which any hop on the Internet can set to a value higher than the guaranteed minimum.
Almost all routers on the Internet are indeed able to send unfragmented packets of up to 1,500 bytes. This is known as the Ethernet II frame format.
You have to subtract both the IP (20 bytes) and TCP (32 bytes) or UDP (8 bytes) header sizes from the MTU to determine the maximum user data (payload) size.
And you ought to subtract another 8 bytes for DSL connections due to the PPoE protocol overhead.
To be on the safe side that gives us the following maximum custom data (payload) size that you can send in a single packet:
- 1,500 – (20 + 8 + 8) = 1,464 Bytes UDP payload
- 1,500 – (20 + 32 + 8) = 1,448 Bytes TCP payload
Unity Transport Max Payload Size
The Unity Transport component has a payload size setting:
Curiously it defaults to 6,144 bytes (6 * 1,024) and only affects unreliable sends. Reliable messages, like RPCs and NetworkVariables, are not affected. Their limit is in the megabytes.
The max payload size has nothing to do with MTU or packet fragmentation! It only has to be increased if you have many objects spawning in the same frame, which causes a corresponding payload error message if the payload buffer is exceeded.
Reasons Why Games Use UDP
Extra ACK packets, a larger header per packet, and handshaking adds avoidable extra traffic when using the TCP protocol.
While packet fragmentation can generally add to latency, TCP is slightly more likely to be affected due to its larger header.
For all these reasons games prefer to use unreliable UDP datagrams whenever possible.
Do note that you can still send reliable messages through UDP, if the necessary algorithm (ACK packets, timeout, re-request, re-send) is implemented by the transport layer as is the case with Unity Transport.
Leave a Reply