如果客户端先发送fin关闭文件描述符那就接受不了服务器发的fin所以要保留读的文件描述符shutdown关闭读或者写或者读写当我们调用close对方也调用close如果还有数据服务器也要保证把数据刷过去再调用close调用close就行操作系统完成。 这只是说有这样的接口。四次挥手小双方发消息完没完不一定是同时的所以ack和fin不能捎带应答所以就是四次挥手有些情况双方都想断开所以也可能三次挥手握手挥手本质都是四次因为他们各自特征决定的。客户端关服务器不关服务器状态进入close wait 客户端状态一直是findwait2,服务器端用完一个文件描述符必须关不关就可能处于closewait一直占用文件描述符这也是资源有限的这叫文件描述符泄露问题客户端最后发出ack就算四次完成而服务器要收到所以客户端要等待一段时间客户端金额入timewait状态客户端调用close()$\rightarrow$ 内核发送FIN第一次挥手 $\rightarrow$ 服务端内核自动ACK第二次挥手。此时客户端已单方面闭门谢客。服务端应用处理完后手也调用close()$\rightarrow$ 服务端内核发送FIN第三次挥手 $\rightarrow$ 客户端内核自动ACK第四次挥手。此时连接彻底寿终正寝。最大报文存活时间一个报文从主机发送到网络发了很多报文有个统计数据统计报文最大生存时间客服端给服务器发的消息某个发送的消息判定超时了超时重发但是这个消息没丢他还在某个路由器卡着四次挥手做完了但是这个消息还是活着。后来客户端关闭后立即再重启端口一致这个报文可能就直接到来了。就可能影响下次连接建立过程和数据通信过程。1. 误区一挥手花的时间 vs 迷路报文能活的时间你把“正常的网络传输时间RTT”和“报文的最大生存时间MSL”混淆了。四次挥手有多快正常情况下四次挥手的报文是在网络中顺畅跑的一来一回RTT通常也就是几十毫秒ms即使慢一点也就几百毫秒。整个四次挥手做完可能连 1 秒钟都不到。MSL 有多长MSLMaximum Segment Lifetime是报文在网络里能存活的极限时间。RFC 793 标准建议是 2 分钟实际工程中Linux 通常设定为 30 秒或 60 秒。发现差距了吗即便四次挥手磨磨唧唧花了 1 秒钟而那个卡在某个拥堵路由器里的“迷路旧报文”它的寿命可是长达 60 秒挥手所花的那点时间根本不足以把这个幽灵报文给“熬死”。等四次挥手结束时那个幽灵报文大概率还活蹦乱跳地在网络里找出路呢。2. 误区二为什么要等“2”个 MSL既然 1 个 MSL 就代表一个报文能活的最长时间等 1 个 MSL 不就行了吗为什么非要等 2 个这 2 个 MSL比如 60秒 × 2 120秒的等待期也就是TIME_WAIT状态其实承担了两个截然不同但都至关重要的保底任务任务 A防旧报文干扰你提到的幽灵报文问题倒计时是从客户端发出第四次挥手最后的 ACK那一刻开始算的。 协议规定等 2MSL是为了提供一个绝对安全的双倍缓冲期。既然网络中最极端的单向延迟是 1MSL那么等待 2MSL 可以 100% 确保在这个连接期间产生的任何报文不管去程还是回程不管迷路多久在这 2MSL 的时间里它们的 TTL存活跳数必定会被扣到 0死在网络中。这样就能保证当端口再次被使用时网络管道里绝对干干净净。任务 B确保服务器能顺利“闭眼”可靠的终止连接这是 2MSL 的另一个核心原因也是为什么刚好是 2 的数学原因。 试想一下四次挥手的最后一步客户端发出了最后的 ACK然后如果客户端直接跑路关机/释放端口会发生什么万一这个最后的 ACK 迷路丢了呢服务器没收到 ACK它会觉得“客户端是不是没收到我的分手信FIN”于是服务器会重新发送 FIN。如果此时客户端已经跑路了服务器就会收到一个 RST 报错服务器会非正常关闭。为了防止这种情况客户端发完最后一次 ACK 后必须留在原地等2MSL去程 1MSL留给最后那个 ACK 走到服务器的最长时间。回程 1MSL如果 ACK 丢了留给服务器重发 FIN 走到客户端的最长时间。如果客户端在原地等了 2MSL依然没有收到服务器重发的 FIN客户端就可以极其自信地断定“看来我最后发的 ACK 对方妥妥收到了没人找我麻烦了我可以安心彻底关闭了”主动断开一方一定是最后能接收数据的一方所以要有等待时间。为了让历史残留报文在网络中消散不会影响下一次网络连接和通信。等待期间来了报文直接丢弃。虽然概率低但是一旦有tcp多设备多连接大概率每天都会实现。主动断开连接一方要进入timewait再次重启并没有close链接还在使用端口号也在使用再次绑定就失败。这样就可以对网络中残留的报文进行丢弃如果最后一次ACK丢失那么对方一定timewait期间没有在收到fin就证明对方收到ack 较大概率保证握手是正常完成的。这样即使服务器崩了也能立即重启但是网络中丢失报文再进来怎么办通信时候服务器做ack时候我知道 客户端从哪发数据如果data序号和期望不匹配也可以丢弃双方握手时双方会进行序号随机化你从多少开始我从多少开始就可以振别出来还会根据缓冲区大小计算上界。滑动窗口看课件7滑动窗口快重传如果收不到三个就用超时重传收到ack滑动窗口右滑就把数据丢弃掉没有收到应答就不要滑动这就是暂存。最左侧丢了1001-2000丢了ack只能1001滑动窗口不动为了进行超时重传和快重传中间丢失滑动窗口首先向右滑动到中间丢失的位置因为根据确认序号的定义是我已经收到的报文就变成最左侧丢失最右边丢了也是向右滑动在丢失部分停下来转化为最左侧丢失所有报文都触发超时重传如果同时收到3个以上相同序号ack取消超时用快重传