一、先理解 TCP 在网络中的位置¶
TCP 属于传输层协议,主要负责端到端的可靠传输。它解决的核心问题有两个:
- 数据要不要先建立连接
- 数据传输过程中是否需要确认、重传和排序
和 TCP 并列的另一个传输层协议是 UDP。TCP 更可靠,UDP 更轻量。
二、认识 TCP 报文里的关键字段¶
学习三次握手和四次挥手之前,先记住几个最常见的标记位:
| 标记位 | 作用 |
|---|---|
| SYN | 发起连接同步请求 |
| ACK | 确认收到对方数据 |
| FIN | 请求断开连接 |
| PSH | 表示开始传输数据 |
另外还有两个很重要的字段:
| 字段 | 含义 |
|---|---|
seq |
序列号,用来标识发送顺序 |
ack |
确认号,用来告诉对方“我收到了哪里” |
三、TCP 三次握手怎么完成¶
TCP 三次握手的核心目标是:客户端和服务端都确认彼此具备收发能力,然后再正式传输数据。
3.1 三次握手的标准流程¶
1、客户端发送 SYN,请求建立连接,并发出一个随机 seq。
2、服务端收到后,回复 SYN + ACK,表示“我收到了你的请求,我也同意建立连接”,同时返回自己的 seq 和客户端的 ack=seq+1。
3、客户端再回复 ACK,确认服务端的响应已经收到。
到这里,连接正式建立,后续才能开始传输业务数据。
3.2 为什么一定是三次,不是两次¶
如果只有两次,客户端虽然知道服务端收到了自己的请求,但服务端并不能确认客户端是否收到了自己的确认包。第三次握手的意义,就是让双方都对连接状态达成一致。
四、TCP 四次挥手怎么完成¶
TCP 断开连接时使用四次挥手。因为断开连接是双向动作,双方都要把“我不发了”和“我也不发了”分别确认清楚。
4.1 四次挥手的标准流程¶
1、客户端发送 FIN,表示自己没有数据要发了。
2、服务端回复 ACK,表示“我知道你准备断开了”。
3、服务端处理完剩余数据后,再发送 FIN,表示“我也发完了”。
4、客户端回复 ACK,最终关闭连接。
4.2 为什么不是三次挥手¶
因为服务端收到客户端的 FIN 后,可能还有数据没发送完,所以只能先回 ACK。等服务端自己也准备关闭时,再单独发送 FIN,这就自然形成了四次挥手。
五、TCP 和 UDP 到底有什么区别¶
| 对比项 | TCP | UDP |
|---|---|---|
| 是否面向连接 | 是 | 否 |
| 可靠性 | 可靠 | 不可靠 |
| 是否有确认和重传 | 有 | 没有 |
| 是否有流控 | 有 | 没有 |
| 开销 | 更大 | 更小 |
| 常见场景 | Web、邮件、文件传输 | DNS、音视频、VoIP |
如果业务更看重数据准确性,优先考虑 TCP;如果更看重实时性和开销,常常使用 UDP。
5.1 UDP 的一个简单实验¶
在一台 Linux 主机上创建 UDP 端口:
yum install -y nc
nc -lu 12306
ss -lntup | grep 12306
另一台主机连接这个 UDP 端口:
nc -u 10.0.0.200 12306
抓包时可以使用:
udp.port == 12306
六、TCP 的 11 种状态怎么记¶
学习 TCP 状态,不是为了死记硬背,而是为了看懂 ss -ant、netstat -ant、抓包结果和排障现象。
6.1 11 种状态总览¶
CLOSEDLISTENSYN_SENTSYN_RCVDESTABLISHEDFIN_WAIT1FIN_WAIT2CLOSE_WAITCLOSINGLAST_ACKTIME_WAIT
6.2 三次握手里的关键状态¶
三次握手最重要的状态变化如下:
1、初始时客户端和服务端都在 CLOSED。
2、服务端启动监听后进入 LISTEN。
3、客户端发起连接后进入 SYN_SENT。
4、服务端收到请求后进入 SYN_RCVD。
5、双方确认完成后都进入 ESTABLISHED。
6.3 四次挥手里的关键状态¶
1、客户端发送 FIN 后进入 FIN_WAIT1。
2、服务端收到 FIN 后进入 CLOSE_WAIT。
3、客户端收到服务端的 ACK 后进入 FIN_WAIT2。
4、服务端发送自己的 FIN 后进入 LAST_ACK。
5、客户端收到服务端 FIN 后进入 TIME_WAIT。
6、服务端收到最后一个 ACK 后进入 CLOSED。
6.4 第 11 种状态 CLOSING 怎么理解¶
CLOSING 比较少见,它表示客户端发了 FIN 之后,没有先收到服务端的 ACK,反而先收到了服务端自己的 FIN。这种情况通常和异常时序或丢包有关。
6.5 必会的重点状态¶
工作里最需要优先掌握的状态是:
CLOSEDLISTENESTABLISHEDTIME_WAITCLOSE_WAIT
其中:
TIME_WAIT多,常说明连接关闭频繁。CLOSE_WAIT多,常说明应用层没有及时关闭连接。
七、用抓包验证三次握手和四次挥手¶
原始笔记给出了一套很适合练手的实验方式:使用 nc 临时起服务端口,再用 Wireshark 抓包观察握手与挥手。
7.1 实验准备¶
yum install -y nc
nc -kl 9999
ss -lntup
如果环境里有防火墙或 SELinux 干扰,也可以先处理:
systemctl stop firewalld
systemctl disable firewalld
systemctl status firewalld
setenforce 0
sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config
getenforce
7.2 抓包观察点¶
Wireshark 过滤条件可以直接用:
tcp.port == 9999
重点观察下面三类报文:
- 客户端发送
SYN - 服务端回复
SYN, ACK - 客户端再回复
ACK
关闭连接时,再观察:
- 客户端
FIN, ACK - 服务端
ACK和FIN - 客户端最终
ACK
八、小结¶
把 TCP 学明白,建议按这条顺序来:
1、先搞清楚三次握手和四次挥手。
2、再理解 TCP 与 UDP 的差异。
3、最后结合 11 种状态去看 ss、netstat 和抓包结果。
这样再去看网络连接问题、端口问题和高并发问题,会更容易定位根因。