# TCP Three-Way Handshake Process: How TCP Establishes Reliable Connections

> Understand the TCP three-way handshake process. Learn how SYN SYN-ACK and ACK establish reliable client-server connections and synchronize sequence numbers.

- Repository: [CyC2018/CS-Notes](https://github.com/CyC2018/CS-Notes)
- Tags: deep-dive
- Published: 2026-02-24

---

**The TCP three-way handshake process is a three-step exchange (SYN, SYN-ACK, ACK) that establishes a reliable connection between client and server while synchronizing initial sequence numbers and preventing stale connection requests.**

The Transmission Control Protocol (TCP) establishes reliable, full-duplex communication through a carefully orchestrated initialization sequence. According to the CyC2018/CS-Notes repository, this **TCP three-way handshake process** ensures both parties agree on initial sequence numbers and protects against delayed or duplicate connection requests. The mechanism is documented in detail in `notes/计算机网络 - 传输层.md` (lines 50-70), which explains how the protocol transitions from a closed state to an established connection.

## How the TCP Three-Way Handshake Process Works

The handshake consists of three distinct segments exchanged between the client and server. Each step serves a specific purpose in synchronizing sequence numbers and confirming readiness for data transfer.

### Step 1: SYN (Synchronize)

The client initiates the connection by sending a TCP segment with the **SYN flag** set and an initial sequence number denoted as **x**. This segment indicates the client's intention to establish a connection and establishes the starting point for sequence tracking. In the CS-Notes source, this is described as the client sending "a TCP segment with the SYN flag set and an initial sequence number x."

### Step 2: SYN-ACK (Synchronize-Acknowledge)

The server responds with a segment containing both **SYN and ACK flags** set. The server acknowledges the client's sequence number by setting `ACK = x + 1`, confirming receipt of the initial SYN. Simultaneously, the server provides its own initial sequence number **y**, requesting synchronization from the client. This dual-purpose segment establishes the server's initial sequence state while validating the client's request.

### Step 3: ACK (Acknowledge)

The client completes the handshake by sending a final ACK segment with `ACK = y + 1`, acknowledging the server's sequence number. Only after this third segment does the connection enter the **ESTABLISHED** state, enabling full-duplex data transfer. According to the CS-Notes analysis, this final acknowledgment prevents the server from opening connections for stale SYN segments that may have been retransmitted after timeouts.

## Why Three Steps Are Necessary

The three-way design specifically guards against **stale connection requests** (also known as delayed or duplicate SYN segments). If the final ACK were omitted, a server might accept a delayed SYN from an earlier, abandoned connection attempt, creating a half-open connection that wastes resources. The third step ensures the client is actively responding to the server's specific request, not merely triggering an old, retransmitted packet.

## TCP Three-Way Handshake Implementation in Code

While application developers rarely implement the handshake manually, understanding where it occurs in socket programming clarifies the abstraction boundary. The operating system kernel handles the three-way handshake automatically when specific socket APIs are invoked.

### Python Client Implementation

When calling `socket.connect()`, the operating system performs the three-way handshake transparently before returning control to the application. The following example from the CS-Notes repository demonstrates a standard TCP client where the handshake completes during the `connect()` call:

```python
import socket

def tcp_three_way_handshake(host: str, port: int = 80):
    # 1️⃣ Create a TCP socket

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        # 2️⃣ Initiate connection – OS sends SYN, receives SYN-ACK, sends ACK

        sock.connect((host, port))
        print(f"Connection to {host}:{port} established (handshake complete).")
        # You can now send/receive data over the reliable TCP stream

        sock.sendall(b'GET / HTTP/1.1\r\nHost: ' + host.encode() + b'\r\n\r\n')
        response = sock.recv(4096)
        print("Received:", response.decode(errors='ignore').splitlines()[0])
    finally:
        sock.close()

if __name__ == "__main__":
    tcp_three_way_handshake("example.com")

```

### C Server Implementation

On the server side, the `accept()` system call blocks until the three-way handshake completes. The kernel handles the SYN, SYN-ACK, and ACK exchange before returning a new file descriptor for the established connection:

```c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

int main() {
    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in srv_addr = {0};
    srv_addr.sin_family = AF_INET;
    srv_addr.sin_addr.s_addr = INADDR_ANY;
    srv_addr.sin_port = htons(8080);

    bind(listen_fd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
    listen(listen_fd, 5);
    printf("Server listening on port 8080...\n");

    int conn_fd = accept(listen_fd, NULL, NULL);   // ← three-way handshake completes here
    printf("Client connected (handshake finished).\n");
    // ... communicate over conn_fd ...
    close(conn_fd);
    close(listen_fd);
    return 0;
}

```

## Summary

- The **TCP three-way handshake process** consists of SYN, SYN-ACK, and ACK segments that establish reliable connections.
- Sequence numbers are synchronized during the exchange: the client starts with **x**, the server responds with **y**, and both acknowledge by incrementing the received value by one.
- The connection enters the **ESTABLISHED** state only after the third acknowledgment, preventing stale or delayed SYN requests from creating spurious connections.
- Application code in `notes/计算机网络 - 传输层.md` and related files demonstrates that the operating system kernel handles the handshake automatically when `connect()` or `accept()` is called.

## Frequently Asked Questions

### What happens if the third ACK in the TCP three-way handshake is lost?

If the final ACK is lost, the server remains in the SYN-RECEIVED state and will retransmit the SYN-ACK segment after a timeout. The client, believing the connection is established, may begin sending data. When the server receives those data packets without having received the ACK, it treats them as out-of-order segments and typically responds with a reset (RST) or discards them, depending on the TCP implementation.

### Can the TCP three-way handshake process be completed in fewer than three steps?

No, the three-step design is fundamental to TCP's reliability. Two steps would allow stale SYN segments to create half-open connections, while four steps would add unnecessary latency. The three-way exchange represents the minimum viable protocol for synchronizing sequence numbers and confirming bidirectional reachability.

### Where is the TCP three-way handshake documented in the CS-Notes repository?

The detailed explanation appears in `notes/计算机网络 - 传输层.md` between lines 50-70, which describes the SYN, SYN-ACK, and ACK sequence. Additional context regarding how applications utilize these connections appears in `notes/计算机网络 - 应用层.md` (around line 160) and [`notes/HTTP.md`](https://github.com/CyC2018/CS-Notes/blob/main/notes/HTTP.md), which discusses persistent connections that reuse a single handshake for multiple requests.

### Does application code manually implement the TCP three-way handshake?

No, the handshake is implemented entirely within the operating system kernel. When an application calls `socket.connect()` in Python or `accept()` in C, the kernel automatically exchanges the three required segments before returning control to the application, as demonstrated in the source code examples from CyC2018/CS-Notes.