Skip to content
Back to all concepts
NetworkingProtocolsTCPPerformance

TCP Handshake & Congestion

The 3-way handshake that powers the internet. SYN, SYN-ACK, ACK. Flow control vs Congestion control, and modern algorithms like BBR.

By ScaleWikiUpdated 3 min readAdvanced

TCP provides a reliable byte stream

  • TCP: A reliable, ordered byte stream while the connection operates. A connection can fail, and an acknowledgment does not prove that the receiving application processed the data.
  • UDP: Datagrams without built-in delivery or ordering guarantees. Applications may add reliability, as QUIC does. TCP specification: RFC 9293.

The 3-Way Handshake Connection

Before sending data, Alice and Bob must agree on Sequence Numbers.

  1. SYN: "Let's talk. My sequence starts at xx."
  2. SYN-ACK: "I hear you (x+1x+1). My sequence starts at yy."
  3. ACK: "I hear you (y+1y+1)."

Connection Termination (4-Way Wave)

  1. Client: FIN "I'm done."
  2. Server: ACK "Roger."
  3. Server: FIN "I'm done too." (Can happen later).
  4. Client: ACK "Bye."

Flow Control vs Congestion Control

These are often confused.

FeatureProblem SolvedMechanism
Flow ControlReceiver is too slow (Buffer overflow)Receive Window (rwnd) sent in ACK headers.
Congestion ControlNetwork (Router) is congestedCongestion Window (cwnd) estimated by Sender.

Congestion Algorithms

  1. Slow Start: Grow the congestion window rapidly as acknowledgments arrive, roughly doubling per RTT under suitable conditions, until a threshold or congestion signal is reached.
  2. Packet Loss: Oops, router dropped a packet.
    • Reno/CUBIC: Use loss signals but have different window-reduction and growth rules; they do not always halve the sending rate.
    • BBR (Model-based): Google's algo. Measures Bandwidth and RTT. "Loss isn't always congestion."

The "Bufferbloat" Problem

Routers have large queues (buffers).

  • Packet Loss algo: Fills the buffer -> Latency increases -> Finally drops packet -> Sender slows down.
  • Result: High latency (Lag) before speed adjusts.
  • BBR approach: Builds a model of bottleneck bandwidth and propagation delay to pace traffic. Its behavior depends on implementation/version; it does not eliminate queues or loss.

Code example: a bounded Python TCP request

This minimal plaintext HTTP example illustrates stream I/O. It is not a full HTTP parser; production HTTP clients should handle TLS, body framing, limits and redirects.

python
import socket

# 1. Create Socket (IPv4, TCP)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5)

# 2. Connect (Triggers 3-Way Handshake)
# Sends SYN
s.connect(("example.com", 80)) 
# Returns once the local TCP connection is established

# 3. Send Data (Push)
msg = "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n"
s.sendall(msg.encode())

# 4. Receive Data
response = b""
while True:
    chunk = s.recv(4096)
    if not chunk: break # Server sent FIN
    response += chunk

s.close() # Sends FIN
print(response.decode("utf-8", errors="replace"))

Interview Tips 💡

  • "Why 3-way handshake?" — To prevent old duplicate connection initiations from confusing the server. Both sides must confirm readiness.
  • "SYN Flood Attack" — Attacker sends thousands of SYNs but never ACKs. Server memory fills up waiting.
    • Defense: SYN Cookies (Stateless handshake until ACK).
  • "Nagle’s Algorithm" — Buffers small writes to send full packets. Bad for real-time games (disable with TCP_NODELAY).
  • "TIME_WAIT" — The endpoint that actively closes normally retains connection state for 2×MSL. The duration and listener-rebind behavior depend on the OS and socket configuration.

Failure exercise: did the order succeed?

A client sends an order, then the TCP connection closes before the response arrives. Transport reliability cannot resolve whether the server committed the order. Retrying blindly can create a duplicate. Give the operation an idempotency key and provide a way to retrieve its result. This separates delivery of bytes from the application’s business outcome.