我教 TCP,我经常遇到一些人,他们被误认为只有在达到窗口大小时才会发送 ACK。这不是真的。(说实话,在我知道得更好之前,我也错误地教了这个,所以我完全理解这个错误)。
注意,我将使用接收器/发送器来描述它,但请记住 TCP 是双向的,并且双方都维护一个窗口大小。
窗口大小(接收方设置)是对发送方可以发送多少字节而不必被迫停下来等待确认的硬限制。
窗口大小不决定接收器应该多久发送一次确认。最初,TCP 协议要求在收到每个段后发送确认。后来,TCP 被优化为允许接收器跳过 ACK 并每隔一个(或更多)发送一个 ACKnowledgment。
TCP 的目标是让发送方不断地发送数据包,没有延迟或中断,因为它不断地接收确认,这样“传输中的字节数”的计数总是小于窗口大小。如果在任何时候,Sender 发送了等于窗口大小的字节数而没有收到 ACK,则它会被迫暂停发送并等待。
在这一切中要考虑的重要事情是往返时间。通常,当您在 wireshark 中研究 TCP 时,您只会看到 TCP 对话中一方的观点,这使得很难推断或真正“看到”RTT 的效果。为了说明 RTT 的效果,看一下这两个捕获。它们都捕获相同的对话,通过 HTTP 下载 2MB 文件,但一个是从Client的角度来看的,另一个是从Server的角度来看的。
注意:如果关闭Wireshark 功能“允许子解剖器重新组装 TCP 流”,则更容易分析 TCP
从服务器端捕获(谁是文件的发送者)注意,服务器在接收到第 14 个数据包中的第一个 ACK 之前连续发送 8 个完整大小的数据包(数据包#的 6-13)。如果您向下钻取那个 ACK,注意客户端的确认是针对在 Packet#7 中发送的段。而客户端在第 20 包中发送的 ACK 来自包#9 中发送的段。
看看客户端确实是如何确认所有其他数据包的。但它几乎似乎是“迟到”承认他们。但实际上,这只是往返时间的影响。发送方能够在第一个段到达客户端和客户端的 ACK 到达服务器所需的时间内发送 7~个段。如果从客户端的角度来看捕获,它看起来非常“干净”,也就是说,它每接收到第二个数据包,就发送一个 ACK。
还要注意在 Packet#23 发生了什么。服务器已经发送了它所能发送的所有内容,因为“传输中的字节数”达到了窗口大小,因此它被迫停止发送。直到下一个 ACK 到达。由于 ACK 会在接收到的每个其他段中出现。每个 ACK 允许发送方再次发送两个新段,在窗口再次满之前,服务器再次被迫暂停。这一直发生到数据包#51,当客户端(接收器)显着增加窗口大小时,允许服务器(发送器)再次开始不受限制地传输数据......至少直到数据包#175,当新窗口填满时。