前言
看到这个标题你可能会说,TCP 连接的建立与断开,这个我熟,不就是三次握手与四次挥手嘛。且慢,脑海中可以先尝试回答这几个问题:
- 四次挥手是谁发起的?
- 如果断电/断网了连接会断开吗?
- 什么情况下没有四次挥手连接也会断开?
这不是面试,而是遇到了实际问题,至于是什么问题,容我先卖个关子,本文也不会解答,后面会有一篇专门的文章来说遇到的问题是啥,所以在讲实际问题之前,先弄懂理论。
正常断开
我们由浅入深,先了解正常情况下 TCP 连接是如何断开的,下图为 TCP 三次握手与四次挥手的经典图(来自《TCP/IP详解卷1》)
在我们的电脑上,可以使用 **python 的 SimpleHTTPServer ** 来快速起一个 http 服务(http 也是基于 TCP 协议),比如这样:
python -m SimpleHTTPServer 20880
再通过 nc 或 telnet 这两个命令来创建 TCP 连接,比如我测试使用 nc 来创建连接
nc -v ip port
Connection to ip port [tcp/*] succeeded!
表示连接成功
我们如何观察这个连接呢?可以通过 netstat 或 lsof 来查看这条"连接",这里我使用 lsof(mac 与 Linux 系统的 netstat 命令不太一样,使用起来有点别扭 )
lsof -i:20880
无论是客户端还是服务端都会占用一个端口,不过服务端端口是固定的,客户端端口是随机的。
如果我们想看 TCP 连接和断开时握手
与挥手
的 TCP 报文怎么查看呢?可以使用 tcpdump 命令
三次握手
tcpdump -A -vv -i any -S host 10.179.245.95
为了方便查看,和上面的经典图放在了一起
这里的参数需要提一下的是 -S
,如果不加 -S
参数看到的第三次握手的ack=1
,与书上的理论不太一样,其实这里只是 tcpdump 简化了展示,想看实际值需要加 -S
这里的 Flags [S]/[S.]/[.]
- [S] 代表 SYN
- [.] 代表 ACK,[S.] 就是 SYN + ACK
四次挥手
命令与抓三次握手相同,我们抓到如下挥手数据
- [F] 代表 FIN
这张图有点奇怪,四次挥手居然变成了三次,这其实是 TCP 协议的实现问题,如果第二次与第三次挥手之间没有数据发送,那么被动断开连接的一方就可能会把第二次的 ACK 与 第三次的 FIN 合并为一次挥手。
当然我也抓到过正常的四次挥手,大概长这样
异常断开
上面铺垫了这么多,现在开始进入正题。
TCP 连接断开是谁发起的
我们来思考一个问题:TCP 连接的断开是