一、先理解 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 -antnetstat -ant、抓包结果和排障现象。

6.1 11 种状态总览

  • CLOSED
  • LISTEN
  • SYN_SENT
  • SYN_RCVD
  • ESTABLISHED
  • FIN_WAIT1
  • FIN_WAIT2
  • CLOSE_WAIT
  • CLOSING
  • LAST_ACK
  • TIME_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 必会的重点状态

工作里最需要优先掌握的状态是:

  • CLOSED
  • LISTEN
  • ESTABLISHED
  • TIME_WAIT
  • CLOSE_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
  • 服务端 ACKFIN
  • 客户端最终 ACK

八、小结

把 TCP 学明白,建议按这条顺序来:

1、先搞清楚三次握手和四次挥手。 2、再理解 TCP 与 UDP 的差异。 3、最后结合 11 种状态去看 ssnetstat 和抓包结果。

这样再去看网络连接问题、端口问题和高并发问题,会更容易定位根因。