记一个诡异的TCP挥手乱序问题
💡
原文中文,约14800字,阅读约需36分钟。
📝
内容提要
本文探讨了TCP连接关闭过程中的问题,通过抓包分析和状态转移监控,确定问题出现在server对乱序的ack和fin包的处理上。经过内核源码分析,发现问题可能出现在对ack的检查上,最终通过修改内核代码验证了假设,确认了问题原因。同时,文章也解释了close()和shutdown()接口的区别,以及server在收到ack后立刻转移为TIMEWAIT状态的原因。
🎯
关键要点
-
本文探讨了TCP连接关闭过程中的问题,主要集中在server对乱序的ack和fin包的处理上。
-
在内核版本linux 5.10.112中,四次挥手过程中由于fin包和ack包乱序,导致连接关闭延迟。
-
server和client几乎同时发送fin包,client先收到server的fin包并回传ack包,但server乱序处理导致未能正确处理client的fin包。
-
经过抓包分析,发现server未能返回正确的ack包,client因此等待超时后重传fin包,才正常关闭连接。
-
文章分析了close()和shutdown()接口的区别,指出server在收到ack后立即转移为TIMEWAIT状态的原因。
-
通过内核源码分析,确认问题出现在对ack的检查上,导致fin包被丢弃。
-
在复现过程中,使用了不同的关闭接口,发现shutdown()不会设置SOCK_DEAD,导致复现失败。
-
最终确认线上环境使用shutdown()关闭连接,导致了与复现场景的不同,验证了假设。
-
总结指出该现象是内核的合法行为,ack的检查逻辑导致了fin包的丢弃。
➡️