Before a single byte of your actual request moves, TCP spends a full round trip just agreeing the connection exists — the three-way handshake. Why it's shaped that way, what closing a connection costs, and what SYN floods and TIME_WAIT actually are.
3 min read
TCP promises reliable, ordered delivery — but that promise requires both sides to agree on starting sequence numbers before any real data is exchanged, so each side can detect loss and reordering from the very first byte. The three-way handshake is that agreement, and it costs one full round trip before your actual request can even begin.
Three messages, but the client can actually start sending data right after sending its ACK (piggybacking is common) — so in practice this costs one full round trip (SYN → SYN-ACK), not three separate ones.
If your server is 150ms away, the handshake alone costs 150ms before your
request even starts — and if it's HTTPS, TLS adds another round trip on top of
that (covered in the next lesson but one). This is the single biggest reason
connection reuse matters so much: HTTP/1.1's Connection: keep-alive and
connection pooling in every serious HTTP client exist specifically to pay this
handshake cost once and reuse the same open connection for many requests, rather
than re-paying it every time.
TCP closes with its own handshake — typically four messages (FIN, ACK, FIN, ACK) since either side can still have data left to send when it decides it's done sending its own. This is why you'll sometimes see a connection described as "half-closed" — one direction has finished, the other hasn't yet.
After closing, the side that initiated the close holds the connection in a
TIME_WAIT state for a while (often ~60 seconds) before fully releasing it —
insurance against a very late, duplicate packet from the old connection being
misinterpreted as belonging to a brand-new one that happens to reuse the same
port. Running netstat on a busy server and seeing hundreds of TIME_WAIT
connections is normal, expected behavior, not a leak — though a server that
opens huge numbers of short-lived outbound connections (rather than reusing a
connection pool) can genuinely exhaust available ports this way, which is a real,
recurring production bug in poorly-pooled services.
A SYN flood is a denial-of-service attack that sends a huge volume of SYN packets and never completes the handshake (never sends the final ACK), forcing the server to hold each half-open connection in memory while it waits — enough of these can exhaust a server's connection table and block real traffic entirely. Modern servers and load balancers defend against this with SYN cookies — a trick that avoids storing per-connection state until the final ACK actually arrives, so a flood of never-completed handshakes costs the server almost nothing to ignore.
You will essentially never construct a TCP handshake by hand — every HTTP client, database driver, and framework does it for you. What you do control directly, and what this lesson should change: whether your code reuses connections (a database connection pool, an HTTP client instance kept alive across requests) or pays a fresh handshake — and possibly a fresh TLS negotiation on top — on every single call, which is one of the most common, invisible performance bugs in real production code.
Check your understanding
A quick comprehension check — not tracked, not graded, just for you.
1. Why does establishing a new TCP connection cost a full round trip before data can be sent?
2. Why is connection reuse (like HTTP keep-alive or connection pooling) important for performance?
3. What is a SYN flood attack, and what does it try to exploit?
Networking Fundamentals