作者回复: 谢谢你的支持,其实排查就是这样,很有趣,满足了像我这样的人的探索的欲望,从中也学习到新的知识,是一种很不错的“学习方法”~
作者回复: 是的,Packet size limited during capture: HTTP truncated的原因就是你说的这个~ HTTP是先发header后发body(如果有body的话)。header和body是否在不同的TCP分段中(严格来说不是“分片”)取决于应用程序往发送缓冲区里写入的速度。理论上说,TCP不认识HTTP,也不知道哪些数据是header哪些是body,所以header没凑满一个MSS就先发出去也是可能的。
作者回复: 关于第一个问题:这确实是一个有点迷惑人的地方,因为没有客户端的代码(特别是5秒超时的时候tcp连接是如何关闭的,用了close还是shutdown,是否有Linger设置等等),我们只能间接的推测,可能是下面这样: 因为http请求数据量不大,可以在初始拥塞窗口里就能一次发送完,所以客户端把HTTP POST的所有报文都一次性发送了出去,但是因为网络问题,没有收到服务端的全部确认,所以有一部分数据滞留在发送缓冲区,并最终由于超时重传和重试机制得以发出(报文8的http body); 到5秒时,应用程序启动了关闭socket的操作,一个FIN报文也进入了发送缓冲区,不过这个报文“运气好”,立刻被成功收到了。 结合上面的情况,就出现了http body反而在FIN后到达的情况。 第二个问题:报文10的seq是正确的,因为服务端还没有http响应,也就是没有真实的数据发送,所以seq还停留在1,这是对的。收到RST的原因,应该还是客户端那头的tcp连接已经被销毁,因为离客户端发起第一个FIN已经过去16秒。虽然16秒还是小于一般TIME_WAIT需要等待的时间(一般是60秒),但是考虑到客户端作为网关,要处理大量的连接,所以可能对TIME_WAIT做了优化(比如控制TW bucket的长度等)。16秒后,客户端认为这个报文已不属于任何连接,所以直接回复RST。而且这个RST没有ack号,这也符合“因为没有连接而回复”的RST的特征。
作者回复: 你的思考很深入,给你点赞! 1. 这个报文8如你所说,应该是公网上漫游延迟后到达的,这也是TCP状态机设计的时候,考虑TIME_WAIT需要等待2MSL时间的原因,因为难保有一些报文会延迟到达,这种延迟在这里已经达到了十多秒。 2. 如果要确认这个判断逻辑,只能看一下wireshark源码了。我推测是因为FIN都已经到达了,那么序列号在FIN之前的报文已经都到达了(哪怕wiresahrk没有看到这个报文)。在FIN之后到达的报文,就被wireshark认为是重传。
作者回复: 这个dupAck是因为客户端发的5号和6号报文之间,数据有间隔,所以服务端回复的ack只能“停留”在数据中断处。如果客户端收到这样的三个dupAck就会启动快速重传。当然这里并没有条件做快速重传了,因为没有凑满三个dupAck。如果还有疑问,可以继续回复我~
作者回复: 你的总结是对的:)确实是我们和客户都对这个微信网关的超时逻辑不熟悉导致的,不过这也给我们带去了经验的积累,以后遇到这类问题,会先查一下几个环节的超时设置,因为有可能就是它们没对齐导致了问题~
作者回复: 哈哈好问题。其实关于499的介绍,一开始看的是官方的简单文档,但不足以说明问题,主要两个原因: 1. 这里的CLIENT CLOSED说的不清晰,为什么关闭?没有更具体的信息 2. 我们的客户是需要更加详细的证据的,比如抓包分析。这是更加重要的原因 源码注释里面的信息更加丰富一些,不过也还是需要结合抓包分析,才足够有说服力:)
作者回复: 这个好办,你可以直接看一下第25讲,也就是抓包分析的回顾、拾遗,和提高。那里有我总结的场景和使用细节。不过还是建议把全专栏都看一遍,实操一下~
作者回复: 你抓取的是什么应用的报文呢?如果是没有加密的http,应该能看到明文;如果是TLS,那确实是密文,也就是你说的乱码了:)
作者回复: 你好,可以参考这里的解答:https://osqa-ask.wireshark.org/questions/39864/the-temporary-file-to-which-the-capture-would-be-saved-could-not-be-opened-invalid-argument/ 简单来说是两步:1. 创建一个目录 2. 把TEMP环境变量的值设置为这个目录的绝对路径 你可以试试~