Title: System Design Adventure - 2A

Subtitle: TCP vs UDP: How Data Actually Travels

Posted by Afsal on 26-Jun-2026

 

Hi Pythonistas!

Last post we learned how client and server talk.
HTTP. HTTPS. TLS.
But something was missing.
We never asked:
How does data actually travel from your laptop to a server thousands of kilometers away?
That's what this post is about.

The Internet Doesn't Send Big Chunks

When you send a request:
the internet doesn't send it as one big block.
It breaks everything into small pieces.
These pieces are called packets.
Your 1MB image:
→ broken into hundreds of small packets
→ each packet travels independently
→ different packets can take different routes
→ they might arrive out of order
→ some might get lost completely

Now the question is:
Who is responsible for making sure all packets arrive correctly?

Two answers.

TCP. And UDP.

First - The Layers

Before we go further a quick mental model.

The internet has layers.

Each layer has one job.

Application Layer  → HTTP, HTTPS       (what you're asking for)
Transport Layer    → TCP, UDP          (how it gets delivered)
Network Layer      → IP                (how it gets routed)
Link Layer         → WiFi, Ethernet    (how bits physically move)

HTTP lives at the Application layer.

TCP and UDP live at the Transport layer.
HTTP doesn't care how data travels.
It just says: "deliver this."
TCP or UDP figure out how.
As a developer:

Application layer → you control everything
Transport layer   → you choose TCP or UDP
Network layer     → OS handles it
Link layer        → hardware handles it
Below Transport — not your problem.

TCP

Transmission Control Protocol.
TCP's job:
make sure every single packet arrives. in order. correctly.
Think of TCP like registered post.
Post office confirms delivery
Lost package? They resend it
Everything arrives in the right order
You get a confirmation
Reliable. But takes more time.

How TCP Works

Three things happen.


1. The Three-Way Handshake

Before any data flows — TCP shakes hands.
Client → Server : SYN        "I want to connect"
Server → Client : SYN-ACK    "OK, I'm ready"
Client → Server : ACK        "Great, let's go"
SYN = synchronize ACK = acknowledge
After this — connection established.
Now data flows.

2. Acknowledgements

Every packet the server receives — it sends back an ACK.
Client sends:   Packet 1
Server replies: ACK 1  "got it"

Client sends:   Packet 2
Server replies: ACK 2  "got it"

Client sends:   Packet 3
No reply...

Client: "Packet 3 lost. Resending."

This is called retransmission.
Nothing gets lost permanently.

3. Ordering

Every packet has a sequence number.
Even if packets arrive out of order:
Arrived:   Packet 3, Packet 1, Packet 2
Reordered: Packet 1, Packet 2, Packet 3
Application always sees data in correct order.

The Cost of TCP

All this reliability has a price.
Latency.
handshake = one round trip before data flows
every packet waits for ACK
lost packets must retransmit
out of order packets wait for missing ones
There is also head-of-line blocking.
Imagine packets are cars on a single lane road.
Car 3 breaks down.
Cars 4, 5, 6 are stuck.
Even if they could go around — they can't.
TCP holds everything up until the missing packet arrives.
For some apps — fine.
For others — disaster.

UDP

User Datagram Protocol.
UDP's job:
send packets as fast as possible. no guarantees.
Think of UDP like dropping flyers from a plane.
no confirmation anyone picked them up
no guarantee they all landed
no guaranteed order
but incredibly fast
Fire and forget.

How UDP Works

No handshake.
No ACKs.
No retransmission.
No ordering.

Just:
Client → Server: Packet
Client → Server: Packet
Client → Server: Packet
Server gets what it gets.
Lost packets stay lost.
Nobody resends anything.

Why Would You Ever Want That?
Sounds terrible. Why use UDP?

Because sometimes speed matters more than perfection.
Video call.
A packet gets lost.
Should Zoom wait, retransmit, play it late?
No.
A delayed frame is worse than a missing one.
Slight glitch → fine. Everyone freezing → terrible.
Online gaming.
Your character's position updates 60 times per second.
One update lost?
Next one arrives in 16ms anyway.
Who cares about the lost one?
Waiting for retransmission = visible lag.
Live streaming.
Slightly pixelated moment → fine.
Buffering → unacceptable.

Who Decides - TCP or UDP?

You. The developer.
When you open a network connection in code:

 

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# UDP

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

SOCK_STREAM → TCP SOCK_DGRAM → UDP
You pick the socket type.
That's the decision point.
Every packet has a protocol field in its header:
Protocol = 6   → TCP
Protocol = 17  → UDP
When a packet arrives at the server:
OS reads that field.
Routes it to the right handler automatically.

How to Decide
Ask these questions:
Can I tolerate lost data?
No  → TCP
Yes → UDP might work

Does order matter?
Yes → TCP
No  → UDP might work

Accuracy first or speed first?
Accuracy → TCP
Speed    → UDP

TCP vs UDP Side by Side
               TCP              UDP
────────────────────────────────────────
Connection      Yes (handshake)  No
Reliability     Guaranteed       Not guaranteed
Ordering        Yes              No
Speed           Slower           Faster
Retransmission  Yes              No
Use case        Accuracy matters Speed matters

Real World Usage
TCP:

Web browsing (HTTP/HTTPS)
Email
File transfers
Database queries
SSH (more on this next post)

UDP:

Video calls (Zoom, Google Meet)
Online gaming
Live streaming
DNS lookups

Ports

One more concept before we finish.
When data arrives at your computer, how does the OS know which app it's for?
Your laptop might be running:
a browser
a Zoom call
a Spotify stream
a game
All receiving packets simultaneously.
The answer: ports.
Every connection has:
IP address → which computer
Port       → which app on that computer
Well-known ports:
80    → HTTP
443   → HTTPS
22    → SSH
5432  → PostgreSQL
3306  → MySQL
6379  → Redis
A connection is uniquely identified by:
Source IP + Source Port + Destination IP + Destination Port
This is called a 4-tuple.
Your OS uses this to route incoming packets to the right application.

The Interesting Case — HTTP/3
Remember HTTP/3 from last post?

HTTP/3 runs on UDP.
Not TCP.
Why?

TCP's head-of-line blocking was hurting performance.
One lost packet blocked everything.
So Google built QUIC on top of UDP.
QUIC implements its own reliability.
One lost packet only blocks that one stream.
Everything else keeps flowing.
Best of both worlds:
UDP speed + custom reliability = QUIC
The lesson:
TCP and UDP are not your only two choices.
You can build custom transport logic on top of UDP.
Games do it.
Google did it.

Mental Model
Packets           → data broken into small chunks
TCP               → guaranteed, ordered, slower
UDP               → no guarantees, faster
Handshake         → TCP's connection setup
ACK               → confirmation packet arrived
Retransmission    → TCP resending lost packets
Head-of-line      → TCP blocking on a lost packet
Ports             → how OS routes packets to right app
4-tuple           → unique ID for every connection
QUIC              → custom reliability built on UDP
Developer control → Application + Transport layers

What Changed for Me

Before this:
I thought data just... travels.
After this:
I realized every byte that reaches your screen
survived a journey 
broken into packets,
routed across the internet,
reassembled in order,
verified, acknowledged, retransmitted if needed.
Or if speed mattered more 
fired and forgotten.
Every millisecond of that journey
is a deliberate engineering decision.

What's Coming Next

Now you know how data travels.

Next:

a tool that uses everything we've learned so far.
TCP for reliability.
Encryption like TLS.
Public/private keys.
All in one.
SSH how developers securely access remote servers.
And how to create tunnels that will change how you work.
See you in Post 2B.