Topic Overview

TCP vs UDP

Compare TCP and UDP protocols, their characteristics, and when to use each.

TCP (Transmission Control Protocol) and UDP (User Datagram Protocol) are the two main transport layer protocols, each with different characteristics and use cases.


TCP (Transmission Control Protocol)

Characteristics:

  • Connection-oriented: Establishes connection before data transfer
  • Reliable: Guarantees delivery, ordered delivery
  • Flow control: Adjusts sending rate based on receiver capacity
  • Congestion control: Adapts to network conditions
  • Full-duplex: Bidirectional communication

Header size: 20-60 bytes

Use cases: Web browsing (HTTP), email (SMTP), file transfer (FTP), database connections


UDP (User Datagram Protocol)

Characteristics:

  • Connectionless: No connection establishment
  • Unreliable: No delivery guarantee, no ordering
  • No flow control: Sends at maximum rate
  • No congestion control: Doesn't adapt to network
  • Lightweight: Minimal overhead

Header size: 8 bytes

Use cases: DNS queries, video streaming, online gaming, VoIP, DHCP


Comparison

FeatureTCPUDP
ConnectionConnection-orientedConnectionless
ReliabilityReliable deliveryBest effort
OrderingOrdered deliveryNo ordering
Flow ControlYesNo
Congestion ControlYesNo
OverheadHigh (20-60 bytes)Low (8 bytes)
SpeedSlowerFaster
Use CaseData integrity criticalSpeed critical

Examples

TCP Example: HTTP Request

// TCP connection establishment
const socket = new TCPSocket();
await socket.connect('example.com', 80); // 3-way handshake

// Send HTTP request
await socket.write('GET / HTTP/1.1\r\nHost: example.com\r\n\r\n');

// Receive response (guaranteed delivery)
const response = await socket.read();

UDP Example: DNS Query

// UDP - no connection
const socket = new UDPSocket();

// Send DNS query
const query = buildDNSQuery('example.com');
await socket.send(query, '8.8.8.8', 53);

// Receive response (may be lost, no guarantee)
try {
  const response = await socket.receive(1000); // 1 second timeout
} catch (timeout) {
  // Retry or use fallback
}

Common Pitfalls

  • Using TCP for everything: Overhead unnecessary for some use cases. Fix: Use UDP when speed > reliability
  • Using UDP for critical data: Data loss unacceptable. Fix: Use TCP or add reliability on top of UDP
  • Not handling UDP packet loss: Assuming delivery. Fix: Implement retry/timeout logic
  • Ignoring TCP overhead: High latency for real-time apps. Fix: Consider UDP with custom reliability

Interview Questions

Beginner

Q: What are the main differences between TCP and UDP?

A:

TCP:

  • Connection-oriented, reliable, ordered delivery
  • Higher overhead, slower
  • Use when data integrity is critical

UDP:

  • Connectionless, unreliable, no ordering
  • Lower overhead, faster
  • Use when speed is critical and some loss is acceptable

Example: HTTP uses TCP (need reliable delivery). DNS uses UDP (speed matters, can retry).


Intermediate

Q: When would you choose UDP over TCP? Give examples.

A:

Choose UDP when:

  1. Real-time applications: Video streaming, gaming (latency critical)
  2. Simple request-response: DNS queries (can retry if lost)
  3. Broadcast/multicast: One-to-many communication
  4. High throughput: When you need maximum speed

Examples:

  • DNS: UDP for queries (fast, can retry)
  • Video streaming: UDP for live video (some packet loss acceptable)
  • Online gaming: UDP for game state (old updates irrelevant)
  • VoIP: UDP for voice (low latency > perfect delivery)

Trade-off: Accept some packet loss for lower latency.


Senior

Q: Design a real-time multiplayer game network protocol. How do you balance reliability and latency? When would you use TCP vs UDP?

A:

Design: Hybrid Approach

class GameNetworkProtocol {
  // Use UDP for game state (position, movement)
  // Use TCP for critical events (player actions, chat)

  // UDP: Fast, unreliable game state
  async sendGameState(state: GameState): Promise<void> {
    const packet = this.serializeState(state);
    await this.udpSocket.send(packet, this.serverAddress);
    // No retry - next update will replace this
  }

  // TCP: Reliable critical events
  async sendPlayerAction(action: PlayerAction): Promise<void> {
    await this.tcpSocket.write(this.serializeAction(action));
    // Guaranteed delivery for important actions
  }

  // Hybrid: UDP with reliability for important state
  async sendImportantState(state: GameState, sequence: number): Promise<void> {
    // Send via UDP
    await this.udpSocket.send(this.serializeState(state, sequence));
    
    // Track for retry if needed
    this.pendingStates.set(sequence, state);
    
    // If no ACK received, retry via TCP
    setTimeout(() => {
      if (!this.acknowledged.has(sequence)) {
        this.sendViaTCP(state, sequence);
      }
    }, 100);
  }
}

Strategy:

  • UDP for frequent updates: Position, movement (30-60 updates/sec)
  • TCP for critical events: Player actions, chat, game events
  • Sequence numbers: Detect missing UDP packets
  • Selective reliability: Retry only important packets via TCP
  • Compression: Reduce UDP packet size

Why this works:

  • Low latency for game state (UDP)
  • Reliability for critical events (TCP)
  • Best of both worlds

Key Takeaways

  • TCP: Reliable, ordered, connection-oriented - use when data integrity critical
  • UDP: Fast, connectionless, unreliable - use when speed/latency critical
  • Trade-off: Reliability vs Speed
  • Choose based on use case: Web (TCP), Gaming (UDP), Video (UDP), File transfer (TCP)
  • Hybrid approach: Use both - TCP for critical, UDP for frequent updates
  • UDP reliability: Can add reliability on top of UDP if needed (QUIC does this)

About the author

InterviewCrafted helps you master system design with patience. We believe in curiosity-led engineering, reflective writing, and designing systems that make future changes feel calm.