TCP Handshake
The TCP 3-way handshake is the process by which a client and server establish a reliable connection before exchanging data. It ensures that both sides are ready to communicate, sequence numbers are synchronized, and the network path is working.
Step-by-Step: TCP 3-Way Handshake
| Step | Sender → Receiver | Description |
|---|---|---|
| 1️⃣ SYN | Client → Server | Client sends a SYN (synchronize) packet with an initial sequence number (e.g., Seq = 100) to start a connection. |
| 2️⃣ SYN-ACK | Server → Client | Server replies with a SYN-ACK: acknowledges client's SYN and sends its own SYN with its own initial sequence number (e.g., Seq = 500, Ack = 101). |
| 3️⃣ ACK | Client → Server | Client sends back an ACK acknowledging the server’s SYN (Ack = 501). Connection is now established. |
Purpose of TCP Handshake in System Design
- Reliability: Ensures both ends are ready and capable of communication.
- Sequence Number Sync: Sets up both sides to track packet order.
- Avoids Half-Open Connections: Prevents unintentional connections caused by dropped packets or old messages.
- Security (partial): Helps mitigate some basic spoofing or replay attacks by requiring return traffic.
Diagram of TCP Handshake
Client Server
| |
| ----------- SYN (Seq=100) --------> |
| |
| <------ SYN-ACK (Seq=500, Ack=101)--|
| |
| ------- ACK (Seq=101, Ack=501) ---->|
| |
Connection Established |
Example Scenario of TCP Handshake
Scenario: Web Client ↔ Web Server (HTTP over TCP) Let’s say a user visits a website (e.g., https://example.com):
- Browser initiates TCP connection to example.com on port 443.
- TCP 3-way handshake happens to establish a reliable connection.
- Once connected, HTTPS handshake begins, followed by HTTP request/response.
Without this TCP handshake, the HTTP request might go to a server that’s not ready, causing dropped data or errors.
TCP Handshake with Node.js
Although Node.js abstracts the actual handshake, here’s how the net module internally triggers it when connect() is called:
Server
const net = require("net");
const server = net.createServer((socket) => {
console.log("Client connected"); // after handshake
});
server.listen(3000, () => {
console.log("Server listening on port 3000");
});
Client
const net = require("net");
const client = net.createConnection({ port: 3000 }, () => {
console.log("Connected to server"); // handshake complete
});
- When client.createConnection() is called:
- OS sends SYN.
- Waits for SYN-ACK.
- Sends ACK.
- Only after that will the "connect" callback fire.
TCP Handshake Use Cases
| Use Case | How TCP Handshake Helps |
|---|---|
| Microservices | Ensures gRPC/HTTP clients don’t send data until backend is ready. |
| Load balancers (e.g., Nginx, HAProxy) | Wait for successful handshake before forwarding requests. |
| API Gateways | Establishes stable connection before passing request to backend service. |
| Database Clients | PostgreSQL or MySQL drivers use handshake before sending queries. |
System Design Considerations of TCP Handshake
| Challenge | Explanation |
|---|---|
| Latency | Adds round-trip time before data starts flowing. |
| Half-open connections | Clients that disconnect improperly can leave resources open on the server. |
| SYN flood attacks | Attackers can send many SYNs without completing handshake, overwhelming the server (Mitigated via SYN cookies or rate limiting). |