我一直在阅读有关 TCP 接收窗口 (RWIN)、最大段大小 (MSS) 和最大传输单元 (MTU) 的内容。我马上就有一些疑问,需要高级用户的帮助!
以下问题基于我使用 Wireshark 和 Win7 客户端查看 TCP 流中的帧:
- 在哪里(在 TCP 流中)可以找到正在使用的 RWIN?是 SYN、SYN-ACK 还是 ACK?我的印象是它在 3 次握手的 SYN 数据包中。
- 远程机器在 ACK 数据包中通过 16425 的“窗口大小值”和 65700 的“计算窗口大小”(Wireshark 指出比例因子为 4,即 16425 * 4 = 65700)表示什么?
- 哪台机器决定传输过程中使用的 RWIN 值 - 客户端还是远程机器?
- 对于 TCP 连接终止,有一个 FIN-ACK 表示远程计算机想要终止连接,随后是来自客户端的 ACK,然后客户端再次发送 RST-ACK,从而关闭连接。在此终止过程中,FIN-ACK 和 ACK 数据包中的 RWIN 值是否有意义,因为它们与三次握手中所述的 RWIN 值有很大不同?
我还有其他一些问题,但这里的答案可能会对它们有影响,所以我应该先等待一些答案:)
谢谢。QF
答案1
好的...先说简单的部分。
MTU 是网络链路上的最大传输单元。基本上,它指定本地网络链路可以处理的数据包大小...这是“第 2 层”大小(通常是以太网),因此 IP、TCP、UDP 和其他标头都计入此值。非常简单。
MSS 是最大段大小。这是在 SYN 数据包(SYN 和 SYN/ACK)中发送的 TCP 值。它指定 TCP 段中可以包含的数据量。它是 TCP 级别项,因此如果 IP 数据包在传输过程中被分割,则 MSS 指的是重新组装的数据包的 TCP 段中的数据量。稍微不那么直接,但仍然很容易弄清楚。
现在事情变得复杂了。
RWIN 是 TCP 接收窗口。它是 TCP 连接接收方在 TCP 标头的“窗口大小”字段中指定的值。窗口在 TCP 连接期间不断调整其大小。TCP 连接的每个方向都有一个窗口。TCP 的端点在 TCP 连接持续期间,对于 TCP 连接方向的当前窗口大小,彼此之间不会完全同步。
好的,请记住,TCP 代表数据字节流。端点将在操作系统中拥有一个内存缓冲区,用于接收连接的 TCP 数据。该缓冲区(至少在理论上)由窗口大小表示。随着数据被放入缓冲区,窗口大小将缩小,而随着应用程序从缓冲区读取数据,窗口大小将增大。
TCP 连接的发送端将不会传输超过窗口大小的数据,直到它收到增加窗口大小的确认数据包为止。
好的...这里再深入一点...
假设单边数据传输,接收方的缓冲区大小为 10 字节。连接开始时,窗口大小为 10。
发送方发送一个包含 5 个字节数据的段。发送方现在认为窗口大小为 5 个字节(它仍然保留这 5 个已发送的字节,以防需要重新传输它们,直到收到它们的确认)。接收方尚未收到数据包,因此它仍然认为其窗口大小为 10 个字节。
然后,发送方发送一个包含 3 个字节数据的段。发送方认为窗口现在的大小为 2 个字节(10 - 5 = 5,5 - 3 = 2)。接收方仍未收到任何数据包,因此它仍认为窗口大小为 10。发送方现在保留 8 个字节的数据以备可能的重传。
接收方收到第一个段,将数据存储到缓冲区并发出确认。需要注意的是,操作系统已收到数据并确认已收到数据,但应用程序仍未收到数据。确认的 ACK 为 5(相对于所选的初始序列号),窗口大小为 5(因为数据仍位于缓冲区中,占用 10 字节缓冲区中的 5 个字节)。
发送方收到 5 个字节的确认,因此它可以丢弃它保留的用于重新传输的前 5 个字节,因为它知道它们已成功到达接收方。但它仍保留第二个段中的其他 3 个字节,因为它们尚未得到确认。发送方看到接收方发送的窗口大小为 5,但从确认号来看,这代表了 5 个字节。发送方知道它已经发送了另外 3 个字节,但尚未收到确认,因此它仍然认为窗口大小为 2 个字节。
发送方现在发出一个包含 2 个字节数据的段。它现在看到 TCP 窗口为零,这意味着它无法再发送任何数据,直到接收方进一步打开窗口。发送方再次保留 5 个字节的数据以备可能的重传(第二个段中的 3 个字节和第三个段中的 2 个字节)。
接收方收到第二个包含 3 个字节的段。现在它的缓冲区中有 8 个字节的数据。它发送一个确认数据包,确认号为 8(相对于初始序列号),窗口大小为 2。这 8 个字节的数据仍位于 OS 缓冲区中。
现在,应用程序从缓冲区读取了 7 个字节的数据。缓冲区现在有 1 个字节的数据。整个窗口大小为 10,但其中有一个字节的数据,因此剩余 9 个字节可用,因此接收方发送一个确认号为 8 的数据包(因为没有收到新数据),但窗口大小现在为 9(而不是之前的 2)。这就是窗口增长的方式,以便发送方可以发送更多数据。
发送方获得 8 个字节的 ACK,窗口大小为 2。发送方可以丢弃第 2 个段中的 3 个字节的数据,但是它已经发送了另外 2 个字节,并且该数据包中的窗口大小为 2,因此发送方仍然看到零大小的窗口并且不能再发送任何数据。
接收方收到包含 2 个字节的第三个段。将这 2 个字节放入缓冲区,留下 7 个字节空闲。它发送一个数据包,其 ACK 为 10(5 + 3 + 2),窗口大小为 7。
发送方收到确认号为 8、窗口大小为 9 的 ACK。它总共已经发送了 10 个字节,因此仍有两个字节未完成,因此它看到窗口大小为 7(9 - 2)。
发送方只需再发送 5 个字节。这完全适合窗口大小,因此它发送了 5 个字节。现在它看到窗口大小为 2,但这并不重要,因为它没有更多数据要发送。它现在保留 7 个字节的数据以备可能的重新传输。
发送方获得确认号为 10、窗口大小为 7 的 ACK。它丢弃来自第 3 个段的 2 个字节,仍保留 5 个字节以备可能的重传。
接收方获得包含 5 个字节数据的第 4 个段,将该数据添加到其缓冲区(不包含 8 个字节),并发送确认号为 15 且窗口大小为 2 的 ACK。
然后,应用程序读取缓冲区中的 8 个字节,因此缓冲区现在为空。接收方发送一个 ACK,其确认号为 15,窗口大小为满的 10。
发送方收到确认号为 15、窗口大小为 2 的 ACK。它现在可以丢弃它保留的最后一个数据,以备可能的重发。它知道所有数据都已到达接收方。它并不真正关心窗口大小为 2,因为它反正没有更多数据要发送了。
发送方收到最后一个 ACK,确认号为 15,窗口大小为 10。
好的,假设就是这样……希望这能帮助您了解接收窗口的工作原理以及由任一方处理的方式。对于在 TCP 连接上以相反方向传输的任何数据,使用序列号、确认号和窗口大小也会发生同样的事情。
带有 FIN 位的数据包中的 RWIN 值应该具有相同的意义。您能给出一个在 wireshark 中看到的示例,以便我们帮助您解释它们吗?