被印证的感觉,真爽!

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 神一般的抓包图

大家好,我是小林。

之前我在公众号解答了一位读者面试腾讯的面试题,问题如下:

1.jpg

当时我看到这个问题也没有思路,后面我就啃了 TCP 源码,把这个问题搞清楚了,就写了这篇文章:TCP 四次挥手收到乱序的 FIN 包会如何处理?

针对这个问题,我也没办法用实验来验证我的结论,所以当时结论是基于啃 TCP 源码得出来的。

但是,就在昨天!

有位读者在工作中抓到跟这个面试题场景类似的抓包图,我看了下,现象跟我之前啃 TCP 源码得出的结论是符合的。

这种被印证的感觉真爽!

我觉得这个案例还是挺有意思的,因为很好的说明是 TCP 传输协议是按序接收的。

所以,先来回顾腾讯一面的这个问题,再来看看跟这个问题相似的抓包图。


回顾问题


这道鹅厂的网络题可能是提问的读者表述有问题。

因为如果 FIN 报文比数据包先抵达客户端,此时 FIN 报文其实是一个乱序的报文,此时客户端的 TCP 连接并不会从 FIN_WAIT_2 状态转换到 TIME_WAIT 状态。

5.png

因此,我们要关注到点是看「在 FIN_WAIT_2 状态下,是如何处理收到的乱序的 FIN 报文,然后 TCP 连接又是什么时候才进入到 TIME_WAIT 状态?」。

我这里先直接说结论:

在 FIN_WAIT_2 状态时,如果收到乱序的 FIN 报文,那么就被会加入到内核中的「乱序队列」,并不会进入到 TIME_WAIT 状态。

等再次收到前面被网络延迟的数据包时,会判断乱序队列有没有数据,然后会检测乱序队列中是否有可用的数据,如果能在乱序队列中找到与当前报文的序列号保持的顺序的报文,就会看该报文是否有 FIN 标志,如果发现有 FIN 标志,这时才会进入 TIME_WAIT 状态

我也画了一张图,大家可以结合着图来理解。

6.png

TCP 源码分析这里我不再说明了,之前也分析过了,感兴趣的详见:TCP 四次挥手收到乱序的 FIN 包会如何处理?


神一般的抓包图


下图是昨天一位读者发给我的抓包图,图中的异常情况,跟前面这个问题的现象有点类似:

7.jpg

你可能会有疑问为什么 TCP 握手时,双方的 seq 都是 0 开始的?这个是抓包图做了优化,显示的是相对值,而不是真实值,显示相对值方便分析。

为了方便文字描述,我针对异常部分的报文进行编号如下:

89.png

图中端口号为 11710 的为客户端,端口号为 8080 的为服务端。另外,编号 4 是客户端发送的 http 请求,抓包图没有显示 TCP 信息,这里文字补充下:编号 4 数据报文 seq = 1,ack = 1,len = 27

编号 6 是 FIN 报文,也就是服务端向客户端发送的 FIN 报文(第一次挥手),但是是一个乱序的 FIN 报文,因为从编号 4 报文中的 ack = 1 知道,客户端期望下一次收到的报文的序列号为 1,而当前收到的 FIN 报文的 seq = 177,这并不是客户端下一次期望收到的报文,所以是乱序的。

客户端收到乱序 FIN 报文后,并不会从 establish 转为 close_wait 状态,而是把这个乱序的 FIN 报文放到内核中的乱序队列。因为如果这时候就进入了 close_wait 状态,就会马上发送 FIN 报文了(第三次挥手),而不会有客户端后面发送的编号 8 和 9 报文的事情了。

编号 8 是应答报文,是客户端对编号 6 乱序 FIN 报文的应答报文,可以看到这个应答报文中 seq = 28,ack=1,因为并不是我期望的下一个报文,所以应答报文中 ack 还是为 1。

编号 7 是数据报文,也就是服务端向客户端发送的数据报文,该报文 seq = 1,ack=28,len=176,因为 seq 为 1,所以是客户端期望收到的报文。客户端收到该报文后,就回了编号 9 应答报文,此应答报文 seq = 28,ack = 178,其中 ack = 178 是告诉服务端:“你发的 seq = 178 之前(不包括seq=178)的报文,我都收到了,我下次期望收到的报文的 seq 为 178”。

客户端收到编号 7 数据报文时还会做一件事情,会检测「乱序队列」中是否有可用的数据,如果能在乱序队列中找到与当前收到报文的序列号「保持的顺序」的报文,就把处于乱序队列的报文移到可以被正常处理的数据队列。比如,这次的案例中,编号 7 报文 seq = 1,len=176 的数据范围是 1~176,而乱序队列中的 FIN 报文的 seq = 177,这两个报文的 seq 正好是保持顺序的,所以会把  FIN 报文从乱序队列中拿出来一起处理,然后发现有 FIN 标志,于是就会转换状态。

所以,客户端在应答完编号 7 数据报文后,就立马发送 FIN 报文了(第三次挥手),接着服务端应答了该报文,至此四次挥手结束。

这个抓包图跟前面这个腾讯的面试题有一点差异,差异在于:

  • 腾讯的面试题是在 FIN_WAIT_2 状态下收到乱序的 FIN 报文(第三次挥手);
  • 抓包图是在 establish 状态收到了乱序的 FIN 报文(第一次挥手);

上面这两种 TCP 状态,收到乱序的 FIN 报文,并不会立即转换状态,只会被内核放到一个乱序队列里。等收到一个序列号符合「接收方」期望收到的序列号的数据包时,会检测「乱序队列」中是否有可用的数据,如果能在乱序队列中找到与当前收到报文的序列号「保持的顺序」的报文,就会看该报文是否有 FIN 标志,如果发现有 FIN 标志,就会转换状态

所以,从这里可以看到, TCP 传输协议是按序接收,如果收到一个乱序的报文时,并且在接收窗口范围内(序列号超过接收窗口范围外的报文就会被丢弃),就会缓存在内核中的乱序队列,不做其他处理。等收到能与乱序队列中报文的序列号保持顺序的报文,才会一起被处理。

TCP 层必须保证收到的字节数据是完整且有序的,所以如果序列号较低的 TCP 报文在网络传输中丢失了,即使序列号较高的 TCP 报文已经被接收了,应用层也无法从内核中读取到这部分数据。

举个例子,如下图:

8.jpg

图中发送方发送了很多个 packet,每个 packet 都有自己的序号,你可以认为是 TCP 的序列号,其中 packet 3 在网络中丢失了,即使 packet 4-6 被接收方收到后,由于内核中的 TCP 数据不是连续的,于是接收方的应用层就无法从内核中读取到,只有等到 packet 3 重传后,接收方的应用层才可以从内核中读取到数据。

完!

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
5月前
|
存储 Java
【JVM】 程序计数器(Program Counter Register)
【JVM】 程序计数器(Program Counter Register)
184 1
|
5月前
|
存储 SQL 关系型数据库
掌握高性能SQL的34个秘诀🚀多维度优化与全方位指南
掌握高性能SQL的34个秘诀🚀多维度优化与全方位指南
|
5月前
|
并行计算 安全 Java
深入理解Java并发编程:从基础到高级
【2月更文挑战第30天】 本文将深入探讨Java并发编程的核心概念和技术,包括线程、锁、同步、并发集合等。我们将从基础知识开始,逐步深入到高级主题,如Fork/Join框架、CompletableFuture和反应式编程。通过本文,你将能够理解并发编程的重要性,掌握Java中实现高效并发的关键技术和方法。
|
运维 负载均衡 OceanBase
第四章:OceanBase集群技术架构(动态扩容和缩容)
第四章:OceanBase集群技术架构(动态扩容和缩容)
517 0
|
10月前
|
SQL 关系型数据库 MySQL
centos8使用yum源安装mysql8
剩下的数据库配置操作,请参考我之前的文章《Centos7.6配置lnmp》里边有详细的介绍。 有好的建议,请在下方输入你的评论。 欢迎访问个人博客 guanchao.site
880 0
|
分布式计算 Spark
Spark 中的 Rebalance 操作以及与Repartition操作的区别
Spark 中的 Rebalance 操作以及与Repartition操作的区别
871 0
|
前端开发 数据可视化 定位技术
百度地图开发:根据指定手绘图纸照片行政区划自定义绘制对应区域边界生成geoJOSN的解决方案
百度地图开发:根据指定手绘图纸照片行政区划自定义绘制对应区域边界生成geoJOSN的解决方案
393 0
百度地图开发:根据指定手绘图纸照片行政区划自定义绘制对应区域边界生成geoJOSN的解决方案
|
算法 NoSQL API
微信支付-业务流程图+时序图梳理微信支付链路+封装对接微信API工具类
微信支付-业务流程图+时序图梳理微信支付链路+封装对接微信API工具类
472 0
|
机器学习/深度学习 人工智能 达摩院
开源!一文了解阿里一站式图计算平台GraphScope
随着大数据的爆发,图数据的应用规模不断增长,现有的图计算系统仍然存在一定的局限。阿里巴巴拥有全球最大的商品知识图谱,在丰富的图场景和真实应用的驱动下,阿里巴巴达摩院智能计算实验室研发并开源了全球首个一站式超大规模分布式图计算平台GraphScope,并入选中国科学技术协会“科创中国”平台。本文详解图计算的原理和应用及GraphScope的架构设计。
开源!一文了解阿里一站式图计算平台GraphScope
|
XML Shell 调度
Apache Oozie-- 实战操作--集成 hue- 定时调度配置|学习笔记
快速学习 Apache Oozie-- 实战操作--集成 hue- 定时调度配置
Apache Oozie-- 实战操作--集成  hue- 定时调度配置|学习笔记