TCP vs UDP & Transport Protocols

0/4 in this phase0/45 across the roadmap

📖 Concept

At the transport layer, two protocols dominate: TCP (Transmission Control Protocol) and UDP (User Datagram Protocol). Understanding when to use each is crucial for system design, especially for real-time systems, streaming, and gaming.

TCP vs UDP Comparison

Feature TCP UDP
Connection Connection-oriented (3-way handshake) Connectionless
Reliability Guaranteed delivery, ordering No guarantee — packets can be lost
Ordering In-order delivery No ordering
Speed Slower (overhead for reliability) Faster (minimal overhead)
Flow control Yes (sliding window) No
Congestion control Yes (slow start, AIMD) No
Use cases Web, Email, File transfer, APIs Video streaming, Gaming, DNS, VoIP
Header size 20-60 bytes 8 bytes

The TCP 3-Way Handshake

Every TCP connection starts with:

  1. SYN: Client sends "I want to connect" (sequence number X)
  2. SYN-ACK: Server responds "OK, I acknowledge X+1, my number is Y"
  3. ACK: Client confirms "I acknowledge Y+1"

This adds 1 round-trip of latency before any data is sent (called connection establishment overhead).

When to Use Each

Use TCP When:

  • Data integrity matters — file transfers, database queries, API calls
  • Ordering matters — financial transactions, message delivery
  • You need reliability — email (SMTP), web pages (HTTP)

Use UDP When:

  • Speed > reliability — live video streaming, online gaming
  • Some packet loss is acceptable — VoIP (a dropped audio frame is better than lag)
  • You need multicast/broadcast — service discovery, DHCP
  • Small, quick messages — DNS queries (single packet, no handshake needed)

Modern Protocols

  • QUIC (used by HTTP/3): Built on UDP but adds TCP-like reliability with lower latency. It eliminates head-of-line blocking and supports connection migration (switching from WiFi to cellular without reconnecting).
  • WebRTC: Uses UDP for real-time audio/video with custom reliability layers on top.

Pro tip: In interviews, if you're designing a real-time system (chat, gaming, video), mention UDP + application-level reliability. For everything else, TCP (via HTTP) is the default.

💻 Code Example

codeTap to expand ⛶
1// ============================================
2// TCP vs UDP — Conceptual Comparison
3// ============================================
4
5// ---------- TCP-like Communication (Reliable) ----------
6
7class TCPConnection {
8 constructor(destination) {
9 this.destination = destination;
10 this.sequenceNumber = 0;
11 this.ackBuffer = new Map(); // Track sent packets awaiting acknowledgment
12 this.receiveBuffer = []; // Buffer for in-order delivery
13 this.connected = false;
14 this.retryTimeout = 1000; // 1 second
15 this.maxRetries = 3;
16 }
17
18 // 3-way handshake
19 async connect() {
20 console.log(`[TCP] Step 1: Sending SYN to \${this.destination}`);
21 const synAck = await this.sendAndWait({ type: 'SYN', seq: this.sequenceNumber });
22
23 console.log(`[TCP] Step 2: Received SYN-ACK (ack=\${synAck.ack})`);
24 await this.send({ type: 'ACK', ack: synAck.seq + 1 });
25
26 console.log('[TCP] Step 3: Connection ESTABLISHED');
27 this.connected = true;
28 this.sequenceNumber = synAck.ack;
29 }
30
31 // Reliable send with acknowledgment and retry
32 async sendReliable(data) {
33 if (!this.connected) throw new Error('Not connected');
34
35 const packet = {
36 seq: this.sequenceNumber++,
37 data,
38 timestamp: Date.now(),
39 };
40
41 for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
42 console.log(`[TCP] Sending packet seq=\${packet.seq} (attempt \${attempt})`);
43
44 try {
45 const ack = await this.sendAndWait(packet);
46 console.log(`[TCP] ✅ Packet seq=\${packet.seq} acknowledged`);
47 return ack;
48 } catch (e) {
49 console.log(`[TCP] ⏳ Timeout for seq=\${packet.seq}, retrying...`);
50 // Exponential backoff
51 await this.sleep(this.retryTimeout * attempt);
52 }
53 }
54 throw new Error(`[TCP] ❌ Failed after \${this.maxRetries} retries`);
55 }
56
57 async sendAndWait(packet) {
58 return new Promise((resolve, reject) => {
59 setTimeout(() => {
60 // Simulate network — 90% success rate
61 if (Math.random() < 0.9) {
62 resolve({ ack: packet.seq + 1, seq: Math.floor(Math.random() * 1000) });
63 } else {
64 reject(new Error('Timeout'));
65 }
66 }, 100);
67 });
68 }
69
70 async send(packet) {
71 return new Promise(resolve => setTimeout(resolve, 50));
72 }
73
74 sleep(ms) {
75 return new Promise(resolve => setTimeout(resolve, ms));
76 }
77}
78
79// ---------- UDP-like Communication (Fast, Unreliable) ----------
80
81class UDPSocket {
82 constructor(destination) {
83 this.destination = destination;
84 this.packetsSent = 0;
85 this.packetsDropped = 0;
86 }
87
88 // Fire-and-forget — no handshake, no acknowledgment
89 send(data) {
90 this.packetsSent++;
91
92 // Simulate 5% packet loss (normal for UDP)
93 if (Math.random() < 0.05) {
94 this.packetsDropped++;
95 console.log(`[UDP] 📦 Packet #\${this.packetsSent} DROPPED (lost in transit)`);
96 return false; // Packet lost — caller doesn't know unless they check
97 }
98
99 console.log(`[UDP] 📦 Packet #\${this.packetsSent} delivered to \${this.destination}`);
100 return true; // No guarantee the receiver actually got it
101 }
102
103 getStats() {
104 return {
105 sent: this.packetsSent,
106 dropped: this.packetsDropped,
107 deliveryRate: ((this.packetsSent - this.packetsDropped) / this.packetsSent * 100).toFixed(1) + '%',
108 };
109 }
110}
111
112// ---------- When to Use Which ----------
113
114// ❌ BAD: Using UDP for file transfer (data corruption)
115function badFileTransferUDP(file) {
116 const udp = new UDPSocket('storage-server');
117 for (const chunk of file.chunks) {
118 udp.send(chunk); // Some chunks WILL be lost!
119 }
120 // File arrives corrupted — missing chunks
121}
122
123// ✅ GOOD: Using TCP for file transfer (guaranteed delivery)
124async function goodFileTransferTCP(file) {
125 const tcp = new TCPConnection('storage-server');
126 await tcp.connect();
127 for (const chunk of file.chunks) {
128 await tcp.sendReliable(chunk); // Every chunk verified
129 }
130 // File arrives complete and in order
131}
132
133// ✅ GOOD: Using UDP for live video streaming
134function liveVideoStreamUDP(videoFrames) {
135 const udp = new UDPSocket('viewer-client');
136 for (const frame of videoFrames) {
137 udp.send(frame);
138 // If a frame is dropped, just show the next one
139 // Re-requesting the old frame would cause visible lag
140 }
141}
142
143// Demo
144console.log('--- UDP Streaming Demo ---');
145const udp = new UDPSocket('viewer');
146for (let i = 0; i < 20; i++) {
147 udp.send(`frame_\${i}`);
148}
149console.log('Stats:', udp.getStats());

🏋️ Practice Exercise

  1. Handshake Trace: Draw the complete TCP 3-way handshake with sequence numbers (SYN seq=100, SYN-ACK, ACK). Then draw a 4-step connection teardown (FIN/ACK).

  2. Protocol Selection: For each scenario, choose TCP or UDP and explain why: (a) Real-time multiplayer game, (b) Email sending, (c) Live sports scoreboard, (d) File backup to cloud, (e) IoT sensor heartbeat.

  3. Latency Calculation: A client in London connects to a server in New York (RTT = 80ms). Calculate the minimum time to establish a TCP connection and send the first data byte. Compare with UDP.

  4. QUIC Research: Research the QUIC protocol (HTTP/3). Explain how it achieves TCP-like reliability over UDP and why it's faster for web browsing.

  5. Head-of-Line Blocking: Explain the head-of-line blocking problem in TCP and how HTTP/2 multiplexing partially solves it. Why does HTTP/3 (QUIC) solve it completely?

⚠️ Common Mistakes

  • Assuming UDP is always faster — UDP is faster for small, independent messages. For large data transfers, TCP's flow control and congestion avoidance can actually be more efficient than naive UDP with application-level retry logic.

  • Forgetting the TCP handshake latency cost — every new TCP connection adds 1 RTT (round-trip time). For mobile users on high-latency networks (200ms RTT), this means 200ms before any data flows. Use connection pooling or HTTP/2 keep-alive to amortize this cost.

  • Using TCP for real-time audio/video — a single lost packet in TCP blocks ALL subsequent data (head-of-line blocking). For real-time media, UDP with application-level loss concealment is always better.

  • Not considering middle devices — firewalls, NATs, and proxies often block or interfere with non-standard UDP traffic. This is why WebRTC has complex ICE/STUN/TURN mechanisms to work around network restrictions.

💼 Interview Questions

🎤 Mock Interview

Practice a live interview for TCP vs UDP & Transport Protocols