引言:网络通信的基石
TCP 三次握手是建立可靠网络连接的基础过程。本文将聚焦核心内容,清晰解析握手过程中的状态转换、关键函数调用,并通过图表直观展示这一机制。
一、三次握手核心流程
Client Server SYN=1, Seq=X (SYN_SENT) SYN=1, ACK=1, Seq=Y, Ack=X+1 (SYN_RCVD) ACK=1, Seq=X+1, Ack=Y+1 (ESTABLISHED) Client Server
步骤解析:
- SYN:客户端发送同步请求(序列号=X)
- SYN-ACK:服务器确认并发送同步(序列号=Y,确认号=X+1)
- ACK:客户端确认(序列号=X+1,确认号=Y+1)
二、状态转换图解
Client 调用connect()
发送SYN 收到SYN+ACK
发送ACK Client_CLOSED Client_SYN_SENT Client_ESTABLISHED Server 调用listen() 收到SYN
发送SYN+ACK 收到ACK Server_CLOSED Server_LISTEN Server_SYN_RCVD Server_ESTABLISHED
关键状态:
- LISTEN:服务端准备接收连接
- SYN_SENT:客户端已发送SYN
- SYN_RCVD:服务端收到SYN并回复
- ESTABLISHED:连接建立完成
三、客户端与服务端关键函数
客户端流程:
c
int sock = socket(AF_INET, SOCK_STREAM, 0); // 创建套接字
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);
connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); // 触发三次握手
服务端流程:
c
int server_fd = socket(AF_INET, SOCK_STREAM, 0); // 创建套接字
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(8080);
bind(server_fd, (struct sockaddr*)&address, sizeof(address)); // 绑定端口
listen(server_fd, 5); // 进入LISTEN状态
int new_socket = accept(server_fd, NULL, NULL); // 接受已建立的连接
函数作用:
函数 | 作用 | 触发状态变化 |
---|---|---|
listen() |
服务端准备接收连接 | CLOSED → LISTEN |
connect() |
客户端发起连接 | CLOSED → SYN_SENT |
accept() |
服务端接受已建立的连接 | 无状态变化 |
四、常见问题解答
1. 为什么需要三次握手?
防止失效的连接请求突然到达服务端:
- 两次握手:服务端收到过期SYN会直接建立连接
- 三次握手:客户端需要确认才能建立连接
2. SYN洪水攻击是什么?
攻击者发送大量SYN但不完成握手,耗尽服务端资源
防御方案:
bash
# 启用SYN Cookies
sysctl -w net.ipv4.tcp_syncookies=1
五、抓包分析要点
使用Wireshark观察:
- SYN包:Flags=0x002 (SYN)
- SYN-ACK包:Flags=0x012 (SYN, ACK)
- ACK包:Flags=0x010 (ACK)
关键字段:
- 序列号:随机初始值
- 确认号:期望接收的下一个序列号
- 窗口大小:接收缓冲区容量
总结
三次握手核心要点:
- 状态转换:SYN_SENT → SYN_RCVD → ESTABLISHED
- 关键函数 :
- 客户端:
connect()
触发握手 - 服务端:
listen()
准备连接,accept()
获取连接
- 客户端:
- 设计目的:可靠地同步序列号,防止无效连接
理解这些核心概念,就能掌握TCP连接的建立机制,为网络编程和故障排查打下坚实基础。