Networking Interview Prep
TCP and UDP

TCP vs UDP

The Complete Comparison

LinkedIn Hook

"Should I use TCP or UDP?"

This is one of those interview questions that sounds simple — and then quietly reveals how deeply you understand distributed systems.

The naive answer: "Use TCP for reliability, UDP for speed."

The real answer is about tradeoffs:

  • A video call that pauses and stutters is worse than one with a tiny audio glitch
  • A database that delivers data out of order is worse than one that is slightly slower
  • An HTTP/3 connection that uses UDP is not unreliable — it just implements reliability differently

The choice between TCP and UDP is not about reliability vs speed. It is about where the reliability logic lives and which latency tradeoffs your application can tolerate.

This lesson breaks down every dimension of the comparison — with a decision framework you can use in interviews and in production.

Full lesson → [link]

#Networking #TCP #UDP #SystemDesign #BackendEngineering #InterviewPrep


TCP vs UDP thumbnail


What You'll Learn

  • The complete side-by-side comparison of TCP and UDP across every dimension
  • The mental model for choosing between them: where does reliability logic belong?
  • Real-world use cases with the reasoning behind each choice
  • What happens when a protocol "uses UDP" but adds reliability on top (QUIC, RTP, DTLS)
  • Common interview scenarios and how to answer the TCP vs UDP question

The Core Mental Model

Before the comparison table, the key insight:

TCP puts reliability inside the transport layer. The operating system's network stack handles retransmission, ordering, flow control, and congestion control. Your application code sees a byte stream — perfectly ordered, no gaps.

UDP puts reliability decisions in the application layer. Your application receives raw datagrams — possibly lost, possibly out of order. If the application needs reliability, it implements exactly the kind it needs.

This is why the question "TCP or UDP?" is really the question: "Who should implement reliability — the OS or the application?"


The Complete Comparison

DimensionTCPUDP
ConnectionRequired — 3-way handshake before dataNone — first packet IS the data
ReliabilityGuaranteed — ACKs, retransmissionNone — lost packets are gone
OrderingGuaranteed — sequence numbers reorderNone — packets may arrive out of order
SpeedSlower — overhead of ACKs, handshake, windowingFaster — minimal overhead
Header size20–60 bytes (minimum 20)8 bytes (fixed)
Flow controlYes — receiver window (rwnd) limits senderNone
Congestion controlYes — slow start, AIMDNone (app's responsibility)
Error detectionYes — checksum (mandatory)Yes — checksum (optional in IPv4)
Error correctionYes — retransmit corrupted/lost segmentsNone — bad datagrams are dropped
Delivery modelStream (continuous byte flow, no message boundaries)Datagram (each packet is a discrete message)
Broadcast/MulticastNo — point-to-point onlyYes — supports broadcast and multicast
StateStateful — both sides maintain connection stateStateless — no connection state
TeardownRequired — 4-way FIN handshakeNone
Resource usageHigher — buffers, timers, state machinesLower — nearly zero per-datagram overhead

Header Comparison

TCP HEADER (minimum 20 bytes)
────────────────────────────────────────────────────────────────
[ Source Port 2B ][ Destination Port 2B ]
[ Sequence Number 4B ]
[ Acknowledgement Number 4B ]
[ Data Offset 4b ][ Reserved 4b ][ Flags 8b ][ Window Size 2B ]
[ Checksum 2B ][ Urgent Pointer 2B ]
[ Options (variable, 0–40B) ]

UDP HEADER (fixed 8 bytes)
────────────────────────────────────────────────────────────────
[ Source Port 2B ][ Destination Port 2B ]
[ Length 2B ][ Checksum 2B ]

TCP uses 2.5× more header space at minimum — for every small packet, this overhead is significant.


Use Case Decision Framework

Choose TCP when:

Data integrity is non-negotiable.

  • Web browsing (HTTP/HTTPS) — a corrupt HTML file produces a broken page
  • Database queries — a lost byte in a SQL response could return wrong results silently
  • File transfer (FTP, SFTP, S3) — a partially downloaded binary file is unusable
  • Email (SMTP, IMAP) — a missing email is worse than a slightly delayed one
  • SSH sessions — a dropped command character could execute the wrong command

Data must be ordered.

  • Any streaming where the consumer processes data in sequence (log streams, database replication)
  • API responses — JSON with missing bytes is not parseable

You want the OS to handle retransmission logic.

  • You do not want to implement retry/ACK logic in your application

Choose UDP when:

Latency matters more than completeness.

  • Live video/audio calls — a retransmitted frame arrives too late to be useful
  • Online gaming — a lost position update is better than a delayed one (player would have moved by then)
  • Real-time sensor data — old readings are irrelevant when new ones are arriving

You need single-packet exchanges.

  • DNS — one packet query, one packet response; retry at application level is trivial
  • DHCP — device has no IP yet; TCP is impossible before having an IP
  • NTP — time sync is a single round-trip

You need broadcast or multicast.

  • Service discovery (mDNS/Bonjour) — one packet broadcast to all devices on the LAN
  • IPTV — one stream delivered to many receivers simultaneously

You want to implement custom reliability.

  • QUIC (HTTP/3) — UDP + TLS 1.3 + custom stream multiplexing + per-stream retransmission
  • RTP — UDP + sequence numbers + timestamps for A/V sync
  • Custom game protocols — UDP + delta compression + selective ACK for priority data

Real-World Examples and Reasoning

HTTP/1.1 and HTTP/2 → TCP

HTTP is stateful in practice: cookies, sessions, request/response pairing. The response must be complete and ordered — a web page with half the HTML is not a web page. TCP provides this at zero application cost.

HTTP/3 → UDP (via QUIC)

HTTP/2 over TCP suffers from head-of-line blocking — if one TCP segment is lost, all HTTP/2 streams on that connection stall waiting for the retransmit. HTTP/3 uses QUIC (UDP-based): each HTTP/3 stream is independent, so a lost packet in stream A does not block stream B. On lossy mobile networks, HTTP/3 can be significantly faster than HTTP/2.

DNS → UDP (with TCP fallback)

DNS queries typically fit in one datagram. UDP means zero setup cost. If the DNS response exceeds the UDP limit (512 bytes, or 4096 with EDNS), or for zone transfers, DNS falls back to TCP.

Video Conferencing (Zoom, Google Meet) → UDP

A video frame 200ms old is useless. When TCP retransmits, it stalls all subsequent frames waiting for the missing one — causing visible freezes. With UDP, a lost frame produces a brief glitch and the video moves on. Zoom's transport protocol is UDP-based with its own RTP/SRTP layer for encryption and sequence tracking.

Online Gaming → UDP

A player's position from 100ms ago is stale — the player has moved. Games send position updates at 64 Hz (every 15ms). They use UDP and implement client-side prediction and server reconciliation. Only truly important events (item picked up, damage dealt) may use reliability mechanisms — and only for those packets.

SSH → TCP

Every character typed in an SSH terminal must arrive in order without loss. A dropped character executing rm -rf / at position 8 instead of /tmp/ would be catastrophic. TCP is the obvious choice.


Code Example 1 — Comparing Overhead

// Illustrates the protocol overhead difference with a realistic small payload

function analyzeOverhead(protocolName, headerBytes, payloadBytes) {
  const totalBytes     = headerBytes + payloadBytes;
  const overheadPct    = ((headerBytes / totalBytes) * 100).toFixed(1);
  const efficiency     = ((payloadBytes / totalBytes) * 100).toFixed(1);

  console.log(`\n${protocolName}`);
  console.log(`  Header:      ${headerBytes} bytes`);
  console.log(`  Payload:     ${payloadBytes} bytes`);
  console.log(`  Total:       ${totalBytes} bytes`);
  console.log(`  Overhead:    ${overheadPct}%`);
  console.log(`  Efficiency:  ${efficiency}%`);
}

// DNS query — a real small UDP datagram
analyzeOverhead("DNS query (UDP)",   8,  29);  // 8B UDP header + ~29B DNS payload
analyzeOverhead("DNS query (TCP)",  20,  29);  // 20B TCP header + ~29B DNS payload (+ 3 handshake packets)

// HTTP request — typical small TCP segment
analyzeOverhead("HTTP GET (TCP)",   20, 100);  // 20B TCP header + 100B HTTP headers
analyzeOverhead("HTTP GET (UDP)",    8, 100);  // Hypothetical — lower overhead per segment

// Large file transfer — overhead becomes negligible
analyzeOverhead("File chunk (TCP)", 20, 1460); // 1460B is typical TCP MSS (max segment size)
analyzeOverhead("File chunk (UDP)",  8, 1472); // 1472B is typical UDP max before fragmentation

// Output shows:
// For small payloads (DNS): UDP saves 12 bytes — meaningful when millions of queries/sec
// For large payloads (file): header overhead drops below 1.4% — protocol choice matters less

Code Example 2 — TCP vs UDP Decision Simulator

// Given an application's requirements, recommend TCP or UDP

function recommendProtocol(requirements) {
  const {
    name,
    latencySensitive,    // true = ms matter; false = correctness matters
    toleratesLoss,       // true = ok to drop some data; false = need all bytes
    needsOrdering,       // true = order matters; false = ok to receive out of order
    messageSize,         // "small" | "large"
    needsBroadcast,      // true = one-to-many; false = point-to-point
    customReliability,   // true = application will implement own reliability
  } = requirements;

  const reasons = [];
  let tcpScore  = 0;
  let udpScore  = 0;

  if (!toleratesLoss)     { tcpScore += 3; reasons.push("Loss intolerance → TCP (guaranteed delivery)"); }
  if (!needsOrdering)     { udpScore += 2; reasons.push("Order not required → UDP (no reordering overhead)"); }
  if (latencySensitive)   { udpScore += 2; reasons.push("Latency-sensitive → UDP (no handshake)"); }
  if (!latencySensitive)  { tcpScore += 1; reasons.push("Latency-tolerant → TCP fine"); }
  if (needsBroadcast)     { udpScore += 3; reasons.push("Broadcast/multicast required → UDP only"); }
  if (messageSize === "small") { udpScore += 1; reasons.push("Small messages → UDP header overhead matters"); }
  if (customReliability)  { udpScore += 2; reasons.push("Custom reliability → UDP (control your own logic)"); }
  if (toleratesLoss && !customReliability) { udpScore += 1; reasons.push("Tolerates loss with no custom logic → UDP simplest"); }

  const recommendation = tcpScore >= udpScore ? "TCP" : "UDP";
  const confidence     = Math.abs(tcpScore - udpScore) > 3 ? "strong" : "marginal";

  console.log(`\n=== ${name} ===`);
  reasons.forEach(r => console.log(`  • ${r}`));
  console.log(`  TCP score: ${tcpScore}  |  UDP score: ${udpScore}`);
  console.log(`  Recommendation: ${recommendation} (${confidence})`);
}

const apps = [
  {
    name: "Database query (PostgreSQL)",
    latencySensitive: false, toleratesLoss: false,
    needsOrdering: true,     messageSize: "large",
    needsBroadcast: false,   customReliability: false,
  },
  {
    name: "Video call (WebRTC)",
    latencySensitive: true,  toleratesLoss: true,
    needsOrdering: false,    messageSize: "small",
    needsBroadcast: false,   customReliability: true,
  },
  {
    name: "DNS resolution",
    latencySensitive: true,  toleratesLoss: true,
    needsOrdering: false,    messageSize: "small",
    needsBroadcast: false,   customReliability: false,
  },
  {
    name: "File download (HTTPS)",
    latencySensitive: false, toleratesLoss: false,
    needsOrdering: true,     messageSize: "large",
    needsBroadcast: false,   customReliability: false,
  },
  {
    name: "LAN service discovery",
    latencySensitive: true,  toleratesLoss: true,
    needsOrdering: false,    messageSize: "small",
    needsBroadcast: true,    customReliability: false,
  },
];

apps.forEach(recommendProtocol);

TCP vs UDP visual 1


Common Mistakes

Mistake 1 — Equating "UDP" with "unreliable application"

UDP is unreliable at the transport layer. But QUIC — which powers HTTP/3 and Cloudflare's entire edge — is UDP-based and is more reliable in practice than HTTP/2 over TCP on lossy networks. The protocol being UDP does not mean the application is unreliable; it means reliability is implemented where the application needs it. Confusing transport reliability with application reliability is a fundamental mistake.

Mistake 2 — Defaulting to TCP for everything because it is "safe"

TCP's guarantees have costs: handshake latency, head-of-line blocking, flow control, congestion control. For an internal microservice making millions of small status check calls per second, TCP connection overhead can become a real bottleneck. Sometimes UDP with application-level retry (or just accepting occasional loss) is genuinely the right engineering decision.

Mistake 3 — Not knowing that UDP can fall back to TCP

DNS is primarily UDP but falls back to TCP for large responses. SIP (VoIP signaling) uses UDP but can use TCP. Knowing that protocols can switch between transports based on conditions — and why — demonstrates deep understanding in interviews.


Interview Questions

Q: You are building a multiplayer FPS game. Would you use TCP or UDP? Why?

UDP. Player position and game state updates are sent at 64 Hz (every 15ms). A position update from 15ms ago is already stale — retransmitting it via TCP would cause the game to stall waiting for a packet whose information is no longer useful. With UDP, lost updates are simply skipped; the client interpolates using the last known state. For critical game events (health changes, item pickups), the game engine implements selective acknowledgement directly on top of UDP.

Q: HTTP/3 uses UDP. Does that mean HTTP/3 is less reliable than HTTP/2?

No. HTTP/3 runs over QUIC, which is built on UDP but implements its own reliability, encryption (TLS 1.3), and stream multiplexing. QUIC is actually more reliable on lossy networks because it eliminates TCP's head-of-line blocking: a lost packet in one HTTP/3 stream does not stall other streams on the same connection, whereas in HTTP/2 over TCP, one lost segment stalls all multiplexed streams.

Q: What is the difference between TCP's byte stream and UDP's datagram model?

TCP presents a continuous byte stream to the application — there are no message boundaries in the stream itself. If you send() two messages, the receiver might recv() them as one combined message or split across multiple reads. UDP preserves datagram boundaries — each sendto() produces exactly one datagram, and each recvfrom() delivers exactly one datagram. Application protocols on TCP must implement their own framing (e.g., HTTP uses Content-Length or chunked encoding to know where one response ends).

Q: When would you prefer TCP over UDP even if speed is important?

When data integrity is non-negotiable regardless of speed. A database query, file transfer, or authentication token must arrive complete and correct — a partially received or corrupted result is worse than a slightly delayed correct one. For these cases, the overhead of TCP's reliability mechanisms is less costly than the bugs introduced by missing or corrupted data.


Quick Reference — Cheat Sheet

TCPUDP
ConnectionRequired (3-way handshake)None
ReliabilityGuaranteed (ACK + retransmit)None
OrderingGuaranteedNone
SpeedSlowerFaster
Header20–60 bytes8 bytes
Flow controlYes (rwnd)No
Congestion ctrlYes (cwnd, slow start)No
BroadcastNoYes
Delivery modelByte streamDatagrams

Use TCP for: HTTP, HTTPS, SSH, databases, email, file transfer, anything where correctness > speed

Use UDP for: DNS, VoIP, gaming, video calls, NTP, DHCP, QUIC, service discovery, real-time telemetry

The key question: Who should implement reliability — the OS network stack or my application?

  • OS (TCP): simpler app code, more overhead, head-of-line blocking risk
  • Application (UDP): more app code, less overhead, fine-grained control

Previous: Lesson 4.2 — UDP — Fast Communication → Next: Lesson 4.4 — Ports & Sockets →


This is Lesson 4.3 of the Networking Interview Prep Course — 8 chapters, 32 lessons.

On this page