TCP vs UDP Guide
TCP vs UDP at a Glance
| Feature | TCP | UDP |
|---|---|---|
| Connection | Connection-oriented (3-way handshake) | Connectionless |
| Reliability | Guaranteed delivery with retransmit | Best-effort, no guarantee |
| Ordering | In-order delivery guaranteed | No ordering guarantee |
| Error checking | Checksum + ACK + retransmit | Checksum only (optional) |
| Flow control | Yes (sliding window) | No |
| Congestion control | Yes (CUBIC, BBR, etc.) | No |
| Header size | 20โ60 bytes | 8 bytes |
| Speed | Slower (overhead) | Faster (low overhead) |
| Broadcast/Multicast | No | Yes |
TCP Three-Way Handshake
Client Server
| |
|-------- SYN (seq=x) ---->| Client initiates
| |
|<-- SYN-ACK (seq=y,ack=x+1) -- Server acknowledges
| |
|---- ACK (ack=y+1) ------>| Connection established
| |
# Connection teardown (FIN-ACK-FIN-ACK)
Use Cases
| Protocol | Best For | Examples |
|---|---|---|
| TCP | Data integrity critical | HTTP/HTTPS, SSH, FTP, email (SMTP/IMAP), databases |
| UDP | Low latency, loss-tolerant | DNS, DHCP, VoIP, video streaming, online gaming, QUIC |
Go TCP Server Example
// TCP Server
ln, err := net.Listen("tcp", ":8080")
if err != nil { log.Fatal(err) }
for {
conn, err := ln.Accept()
if err != nil { continue }
go func(c net.Conn) {
defer c.Close()
buf := make([]byte, 1024)
n, _ := c.Read(buf)
c.Write(buf[:n]) // echo back
}(conn)
}
// UDP Server
addr, _ := net.ResolveUDPAddr("udp", ":9090")
conn, _ := net.ListenUDP("udp", addr)
defer conn.Close()
buf := make([]byte, 1024)
for {
n, remoteAddr, _ := conn.ReadFromUDP(buf)
conn.WriteToUDP(buf[:n], remoteAddr)
}
QUIC โ Modern Alternative
| Aspect | Detail |
|---|---|
| Transport | Built on UDP, adds reliability in user space |
| Handshake | 0-RTT or 1-RTT (vs TCP+TLS 2-3 RTT) |
| Multiplexing | No head-of-line blocking (unlike HTTP/2+TCP) |
| Migration | Connection survives IP changes (mobile roaming) |
| Used by | HTTP/3, Google services, Cloudflare |