速读原著-TCP/IP(拥塞举例)
第21章 TCP的超时与重传
21.8 拥塞举例(续)
通过使用t c m d u m p和插口排错选项(在第 2 1 . 4节进行了介绍)来观察一个连接,就会在发送每一个报文段时看到 c w n d和s s t h re s h的值。如果M S S为2 5 6字节,则c w n d和s s t h re s h的初始值分别为2 5 6和6 5 5 3 5字节。每当收到一个 A C K时,我们可以看到 c w n d增加了一个M S S,取值分别为512, 768, 1024, 1280等。假定不会发生拥塞,则最终拥塞窗口将超过接收方的通告窗口,意味着通告窗口将对数据流进行限制。
一个更有趣的例子是观察在拥塞发生时的情况。使用与 2 1 . 4节同样的例子。当这个例子运行时发生了4次拥塞。为建立连接而发送的初始 S Y N有一个因超时而引起的重传(见图 2 1 - 5),接着在数据传输过程中有3个分组丢失(见图2 1 - 6)。
图2 1 - 9显示了当初始 S Y N重传并接着发送了前 7个数据报文段时变量 c w n d和s s t h re s h的值(在图2 1 - 2中显示了最初的数据报文段及其 A C K之间的交换过程)。使用t c p d u m p的记号来表示数据字节:1 : 2 5 7 ( 2 5 6 )表示第1 ~ 2 5 6字节。
当S Y N的超时发生时,s s t h re s h被置为其最小取值( 5 1 2字节,在本例中表示 2个报文段)。为进入慢启动阶段,c w n d被置为1个报文段(2 5 6字节,与当前值一致)。
当收到S Y N和A C K时,没有对这两个变量做任何修改,因为新的数据还没有被确认。当ACK 257到达时,因为c w n d小于等于s s t h re s h,因此仍然处于慢启动阶段,于是将 c w n d增加2 5 6字节。当收到ACK 513时,进行同样的处理。
当ACK 769到达时,我们不再处于慢启动状态,而是进入了拥塞避免状态。新的 c w n d值按以下方法计算:
考虑到c w n d实际上以字节而非以报文段来维护,因此这就是我们前面提到的增加 1 /c w n d。在这个例子中我们计算
为8 8 5字节(使用整数算法)。当下一个ACK 1025到达时,我们计算
为9 9 1字节(在这些表达式中包括了不正确的 2 5 6 / 8项来匹配实现计算的数值,正如我们在前面标注的那样)。
这个c w n d持续增加一直到在图 2 1 - 6所示的发生在 1 0秒左右的第1次重传。图2 1 - 1 0是使用与图2 1 - 6相同数据得到的图表,并给出了 c w n d增加的数值。
本图中c w n d的前6个值就是我们为图2 1 - 9所计算的数值。在这个图中,要想直观分辨出在慢启动过程中的指数增加和在拥塞免过程中的线性增加之间的区别是不可能的,因为慢启动的过程太快。
我们需要解释在重传的 3个点上所发生的情况。回想起每个重传都是因为收到 3个重复的A C K,表明1个分组丢失了。这就是 2 1 . 7节的快速重传算法。 s s t h re s h立即设置为当重传发生时正在起作用的窗口大小的一半,但是在接收到重复 A C K的过程中c w n d允许保持增加,这是因为每个重复的A C K表示1个报文段已离开了网络(接收 T C P已缓存了这个报文段,等待所缺数据的到达)。这就是快速恢复算法。
与图2 0 - 9类似,图2 1 - 1 0表示了c w n d和s s t h re s h的数值。第一列上的报文段编号与图 2 1 - 7对应。
c w n d的值一直持续增加,从图 2 1 - 9中对应于报文段1 2的最终取值(1 0 8 9)到图2 1 - 11中对应于报文段5 8的第一个取值( 2 4 2 6),而s s t h re s h的值则保持不变( 5 1 2),这是因为在此过程中没有出现过重传。
当最初的2个重复的A C K(报文段6 0和6 1)到达时它们被计数,而 c w n d保持不变(也就是图2 1 - 1 0中处理重传之前的平坦的一段)。然而,当第3个重复的A C K到达时,s s t h re s h被置为c w n d的一半(四舍五入到报文段大小的下一个倍数),而c w n d被置为s s t h re s h加上所收到的重复的A C K数乘以报文段大小(也即1 0 2 4加上3倍的2 5 6),然后发送重传数据。
又有5个重复的A C K到达(报文段64~66, 68和7 0),每次c w n d增加1个报文段长度。最后一个新的A C K(报文段7 2段)到达时,c w n d被置为s s t h re s h(1 0 2 4)并进入正常的拥塞避免过程。由于c w n d小于等于s s t h re s h(现在相等),因此报文段的大小增加到 c w n d,取值为1 2 8 0。当下一个新的A C K到达(没有在图2 1 - 11中表示出来)时,c w n d大于s s t h re s h,取值为1 3 6 3。在快速重传和快速恢复阶段,我们收到报文段 6 6、6 8和7 0中的重复的A C K后才发送新的数据,而不是在接收到报文段 6 4和6 5中重复的A C K之后就发送。这是 c w n d的取值与未被确认的数据大小比较的结果。当报文段 6 5到达时, c w n d为2 0 4 8,但未被确认的数据有 2 3 0 4字节(9个报文段:46, 48, 50, 52, 54, 55, 57, 59和6 3),因此不能发送任何数据。当报文段6 5到达后,c w n d被置为2 3 0 4,此时我们仍不能进行发送。但是当报文段 6 6到达时,c w n d为2 5 6 0,所以我们可以发送1个新的数据报文段。类似地,当报文段 6 8到达时,c w n d等于2 8 1 6,该数值大于未被确认的2 5 6 0字节的数据大小,因此我们可以发送另 1个新的数据报文段。报文段 7 0到达时也进行了类似的处理。
在图2 1 - 1 0中的时刻1 4 . 3发生下一个重传,也是因为收到了 3个重复的A C K。因此当另一个A C K到达时,可以看到c w n d以同样的方式增长,之后降低到 1 0 2 4。 图2 1 - 1 0中的时刻2 1 . 1也是因为收到了重复的 A C K而引起了重传。在重传后收到了 3个重复的A C K,因此观察到c w n d增加3个,之后降低到 1 2 8 0。在传输的后面部分, c w n d以线性方式增加到最终值3 6 1 5。