现在有一个场景,假设机器 A 启动了一个 TCP Server,机器 B 启动了一个 TCP Client,并且 TCP Client 与 TCP Server 创建好了连接。此时将 A 的网线拔掉会出现什么情况呢?为了先得出直观的结构,可以先做一个简单的实验测试一下
1. 当 TCP 链路创建好拔掉网线
-
在机器 A 与机器 B 都启动
tcpdump
进行抓包 -
机器 A 启动 TCP Server 程序。机器 B 启动 TCP Client 程序,并成功连上机器 A 的 TCP Server。
此时用
netstat
分别在两台机器上面都可以看到该 TCP 链路处于 ESTABLISH 状态 -
机器 B 的 TCP Client 发送消息给机器 A 的 TCP Server
机器 A 的 TCP Server 可以成功接收到机器 B 发送过来的消息
-
断开机器 A 的网线,查看链路状态
此时用
netstat
分别在两台机器上面都可以看到该 TCP 链路仍处于 ESTABLISH 状态 -
机器 B 的 TCP Client 发送消息给机器 A 的 TCP Server
-
打开机器 A 的抓包可以看到在链路断开之后发送的那条 TCP 消息在不断的重传
从这里可以看出 TCP 的链路状态,只是表示 TCP 的会话状态并不代表底层的数据链路状态,即使底层链路断开了,在 TCP 层没有收到通知的情况下,链路状态还是 ESTABLISH。
2. 恢复连接,机器 B 以相同的 IP 与端口向机器 A 发起连接
在完成上面那些操作之后,机器 A 的 TCP Server 还在监听,并且链路还是是 ESTABLISH 状态。此时退出机器 B 的 TCP Client 程序并插上机器 A 的网线,然后 B 绑定与之前相同的IP与端口向 A 建立 TCP 连接,此时会发送什么呢?
通过抓包可以看到,机器 B 首先按照正常三次握手流程发送 SYN,但是 A 返回了一个异常的 ACK,然后 B 发送一个 RST 结束原来的链路。在结束完旧的链路之后B 再次发送 SYN 走三次握手的流程重新建立链路。需要注意的是这个过程对于 B 应用层是不可见的,应用只知道 connect
返回的结果是正确的。
附件
- [Machine A](https://blog.dongliu.site/upload/2024/11/Machine A.pcap)
- [Machine B](https://blog.dongliu.site/upload/2024/11/Machine B.pcap)