TCP Three-Way Handshake Process: How TCP Establishes Reliable Connections
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:
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:
#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/计算机网络 - 传输层.mdand related files demonstrates that the operating system kernel handles the handshake automatically whenconnect()oraccept()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, 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →