TCP协议中Window Scale Option问题【完全解决】
时间:2010-01-13
来源:互联网
在24.4 Window Scale Option中有如下文字:
We saw an example of this option in Figure 18.20. The 1-byte shift count is between 0 (no scaling performed) and 14. This maximum value of 14 is a window of 1,073,725,440 bytes (65535 × 2^14).
这里我没有懂的是为啥scale的最大范围是左移14位,即2^14次幂,这个14是如何得到的?
我查阅了下rfc1323,其中有针对这个14的计算来由,但是不幸的是,该rfc中和14有关的地方我仍然没有明白,所以非常郁闷,请大家帮帮我,下面是rfc1323中有关的内容:
2.3 Using the Window Scale Option
...
TCP determines if a data segment is "old" or "new" by testing
whether its sequence number is within 2**31 bytes of the left edge
of the window, and if it is not, discarding the data as "old". To
insure that new data is never mistakenly considered old and vice-
versa, the left edge of the sender's window has to be at most
2**31 away from the right edge of the receiver's window.
这里rfc1323在推导14这个数时,有上面一段话,其中说明了一个数据分段的序号如果距滑动窗口左边沿2**31次幂之内,则都不是old数据,这里我不明白这个31是如何得到的
[ 本帖最后由 jiufei19 于 2010-1-20 11:56 编辑 ]
作者: jiufei19 发布时间: 2010-01-13
--------------------------------------------------------------------------------------
TCP determines if a data segment is "old" or "new" by testing
whether its sequence number is within 2**31 bytes of the left edge
of the window, and if it is not, discarding the data as "old". To
insure that new data is never mistakenly considered old and vice-
versa, the left edge of the sender's window has to be at most
2**31 away from the right edge of the receiver's window.
Similarly with the sender's right edge and receiver's left edge.
Since the right and left edges of either the sender's or
receiver's window differ by the window size, and since the sender
and receiver windows can be out of phase by at most the window
size, the above constraints imply that 2 * the max window size
must be less than 2**31, or
max window < 2**30
Since the max window is 2**S (where S is the scaling shift count)
times at most 2**16 - 1 (the maximum unscaled window), the maximum
window is guaranteed to be < 2**30 if S <= 14. Thus, the shift
count must be limited to 14 (which allows windows of 2**30 = 1
Gbyte). If a Window Scale option is received with a shift.cnt
value exceeding 14, the TCP should log the error but use 14
instead of the specified value.
可以看出2**31次幂的结果是最关键的地方,这个明白了,后面的就说得通了,我就是看不懂这个地方,我的疑问是既然tcp的序号空间范围是32bit,超过后会回绕序号,那么2**31次幂的意思就是将该范围划分为相等的2部分,即2**32/2=2**31,为啥是这样呢?
另外,我对原文中所提到的“old”和“new”的含义不是很明白其准确含义?
[ 本帖最后由 jiufei19 于 2010-1-16 11:01 编辑 ]
作者: jiufei19 发布时间: 2010-01-14
--------------------------------------------------------------------------------------
Even though a 32-bit space is now allowed for the actual window size, the maximum data size is not 4 GB (2**32 ), but rather 1 GB (2**30 ). This is done so that a TCP receiver can uniquely identify an incoming data segment as a new segment. There is no possibility of old and new segments with the same sequence number arriving out of turn and confusing the receiver, as sequence numbers themselves are in the 32-bit space.
为啥这样只利用原来的4G范围的四分之一,即1G,就能保证接收方不会混淆老数据和新数据?
(1) 什么是所谓的新数据,什么是所谓的老数据?
(2) 难道二分之一不行?
[ 本帖最后由 jiufei19 于 2010-1-16 10:59 编辑 ]
作者: jiufei19 发布时间: 2010-01-14
作者: hritian 发布时间: 2010-01-16
作者: jiufei19 发布时间: 2010-01-16
作者: jiufei19 发布时间: 2010-01-16
snd.una
snd.nxt snd.una + snd.wnd
+----------+
| Sender |
+----------+ 2**31 2**32
+---------------------+-----------------------+
+-----------+
| Receiver |
+-----------+
rcv.wup rcv.wup+rcv.wnd
rcv.nxt
[ 本帖最后由 jiufei19 于 2010-1-18 10:40 编辑 ]
作者: jiufei19 发布时间: 2010-01-18
1、序号空间大小是2**32,而所有和窗口大小有关的值都应满足2的整数次幂,所以窗口大小只能是2**32,2**31,2**30,...,所以现在我们要分析的就是2**32不能被用来表示最大可以使用的窗口值
2、在建立连接的TCP收发双方初始时刻,这个时刻是snd.una和rcv.wup + rcv.wnd之间相差最大的时候,于是我们有如下关系:
snd.una
snd.nxt snd.una + snd.wnd
+---------------------+
| Sender |
+---------------------+
+---------------------+----------------------+
0 2**31-1 2**32-1
+---------------------+
| Receiver |
+---------------------+
rcv.wup rcv.wup+rcv.wnd
rcv.nxt
根据TCP滑动窗口的概念,其表示发送方在未收到接收方的确认前,所能发送的最大数据,那么根据上图我们可以看出如果这个最大数据为2**32的话,即表示一个窗口就可以填满整个序号空间的值,那么此时当发送方收到确认后,序号回绕就立刻发生了,因此就会造成之前窗口中部分被延迟分段的序号和新窗口中的序号发生重叠,显然,由于此时TCP还没有引入timestamps的选项,所以这种情况导致接收方产生混乱。
因此,2**32不能作为最大的窗口值,并且由于窗口大小必须是2的整数次幂,于是我们就知道了上图中|snd.una - (rcv.wup + rcv.wnd)| <= 2**31,即这个差的绝对值最大只能是32bit序号空间的一半,此时,发方最多发送2**31字节数据,若还没有收到收发的ACK,则发方必须等待,显然这个初始状态的差值是最大的,并且只有满足在此2**31范围内,则老数据和新数据(序号回绕后)绝对不会重叠。以后发送窗口和接收窗口都会随着时间平移,但保持这个差值不大于2**31是恒定的
[ 本帖最后由 jiufei19 于 2010-1-18 14:12 编辑 ]
作者: jiufei19 发布时间: 2010-01-18
自己顶下,这2天我又反复阅读了rfc1072等文档,那几个rfc似乎给出了如下示意图,我对此只是模模糊糊理解,但是详细分析,又觉得不甚了了
snd.una
snd.nxt snd.una + snd.wnd
+----------+
| ...
查了一下,没有找到2**31的出处。可能没有我们想像的那么复杂,可能就是一个判断sequence wrap问题的一个最loose的规定(在PAWS出现之前)。在实际的tcp/ip stack的实现中,窗口不可能有那么大,所以一般就是判断收到的segment的sequence有没有在窗口内就可以了。
"the sender and receiver windows can be out of phase by at most the window size"
sender和receiver的窗口有可能out-of-phase,最坏的情况有可能就是sender发了一窗口的数据,receiver都收到了,但是reciever的ack都没有到达sender,这样就出现了rfc1323所说的out-of-phase一个窗口的情况。receiver想收rcv.wup+rcv.wnd开始的数据,而sender可能重发它窗口的left edge的数据。
sender窗口的left edge和receiver窗口的right edge不能超过2**31。否则reciever就会直接把sender可能重发的数据直接丢掉了。在这种情况下得到了max window是2**30。
snd.una
snd.nxt snd.una + snd.wnd
+----------+
| Sender |
+----------+ 2**31 2**32
+-----------------------+-----------------------+
+-----------+
| Receiver |
+-----------+
rcv.wup rcv.wup+rcv.wnd
rcv.nxt
作者: eexplorer 发布时间: 2010-01-19
sender窗口的left edge和receiver窗口的right edge不能超过2**31。否则reciever就会直接把sender可能重发的数据直接丢掉了。在这种情况下得到了max window是2**30。
>> 我们先假定那个2**31的概念是先验的,不需要推导,根据本帖子的如下图示,的确表示收发双方out-of-phase的情况
snd.una
snd.nxt snd.una + snd.wnd
+----------+
| Sender |
+----------+ 2**31 2**32
+---------------------+-----------------------+
+-----------+
| Receiver |
+-----------+
rcv.wup rcv.wup+rcv.wnd
rcv.nxt
那么当接收方的右边界rcv.wup+rcv.wnd - snd.una > 2**31后,为啥接收方会丢掉重发的数据?或者换句话讲,即便不大于2**31,重发的数据因为之前已经被收到了,只是ACK尚未到达发送方,因此发送方若重发的话,这样就不丢掉了吗?另外接收窗口右边界的位置是受接收方应用进程的控制,所以,假设在发生out-of-phase后,接收方应用若读取了部分数据,那么其右边界可能超过了2**31的位置,难道这个情况不可能吗?我感觉我某个地方对滑动窗口理解有错误了。这里我感觉正是因为2**31预先认为是正确的,所以才有上图中发送和接收窗口错开的情况,并且因为初始时刻接收方缓存大小是固定的,而且假定一直不发生改变,于是我们有:
snd.una
snd.nxt snd.una + snd.wnd
+----------+
| Sender |
+----------+ 2**31 2**32
+---------------------+-----------------------+
+-----------+
| Receiver |
+-----------+
rcv.wup rcv.wup+rcv.wnd
rcv.nxt
这样,当发送方发送了这里的2**30字节,即整个窗口后,接收方都收到后,并且返回的ACK假定都未到达发方,此时才发生了上述的out-of-phase情况
PS:
之所以我对这里2**31,窗口扩大因子14等等有疑问是我感觉我对滑动窗口的概念存在不清晰的地方,望不吝赐教哈!
[ 本帖最后由 jiufei19 于 2010-1-19 10:46 编辑 ]
作者: jiufei19 发布时间: 2010-01-19
> 数据?或者换句话讲,即便不大于2**31,重发的数据因为之前已经被收到了,
> 只是ACK尚未到达发送方,因此发送方若重发的话,这样就不丢掉了吗?
是同样都丢掉了,但是情况稍微有些不同。按照2**31的规定,如果receiver收到超过2**31的包的话,就因为too old而直接丢掉了。而如果在2**31的范围内的话,就需要处理duplicate包的情况,即需要告诉sender它收到了duplicate的数据包。
> 另外接收窗口右边界的位置是受接收方应用进程的控制,所以,假设在发生out-of-phase后,
> 接收方应用若读取了部分数据,那么其右边界可能超过了2**31的位置,难道这个情况不可能
> 吗?
这当然是有可能的,但是我们只是在讨论一种极端的情况,以推出max window的大小,没必要深究更detail的情况。
作者: eexplorer 发布时间: 2010-01-19
snd.una
snd.nxt snd.una + snd.wnd
+---------------------+
| Sender |
+---------------------+
2**31 2**32
+---------------------+-----------------------+
+-----------------------+
| Receiver |
+-----------------------+
rcv.wup rcv.wup+rcv.wnd
rcv.nxt
[ 本帖最后由 jiufei19 于 2010-1-19 13:42 编辑 ]
作者: jiufei19 发布时间: 2010-01-19
1、根据我最前面的分析,已经知道了|snd.una - rcv.wup+rcv.wnd|<=2**31是合理的,即发送窗口最左边的数据序号和接收窗口的最大可接收数据序号只要相差在2**31,即半个32bit序号空间大小,那么old和new数据就肯定不会混淆(这是肯定的,因为一半的使用率完全限制了回绕造成的冲突)。不过要注意这里的不会混淆的代价是网络速率虽然可能较高了,但不是很高,也即在不采用PAWS的算法下,该tcp的吞吐量不是很受影响,换句话讲,如果网络速度非常高,则限制为32bit一半的序号空间的做法,虽然可以避免回绕带来的混淆问题,但是却会造成严重的吞吐量下降,此时必须引入PAWS算法来避免序号的快速回绕
2、在满足1的序号条件下,则发送和接收的最大out-of-phase情况只能是如下情况,此时实际发送和接收窗口只能是2**31的一半,即2**30
snd.una
snd.nxt snd.una + snd.wnd
+----------+
| Sender |
+----------+
2**31 2**32
+----------------------+-----------------------+
+ ----------+
| Receiver |
+- ---------+
rcv.wup rcv.wup+rcv.wnd
rcv.nxt
[ 本帖最后由 jiufei19 于 2010-1-19 13:44 编辑 ]
作者: jiufei19 发布时间: 2010-01-19
另外,我还有一个不解就是,为啥不能出现下面的这个方式呢,即窗口大小为2G,这样就恰好应证了我之前的那个2**31的分析了:
snd.una
snd.nxt snd.una + snd.wnd
+---------------------+
| ...
在这种情况下,如果receiver收到一个seq = 0的数据包,那它就不能区分是新的还是旧的了。可能这就是tcp规定2**31的原因了。。。
作者: eexplorer 发布时间: 2010-01-19
因为之前一个窗口的seq=0的序号分段虽然已经收到了,导致接收窗口的右边沿到了2**32-1,但是由于此时发送方没有收到应答,于是可能重发了一个seq=0的分段,但是此时即将发送的一个新分段的seq也为0,于是接收方可能将这个新0分段当成了老的
作者: jiufei19 发布时间: 2010-01-19
eexplorer是否是这个意思:
因为之前一个窗口的seq=0的序号分段虽然已经收到了,导致接收窗口的右边沿到了2**32-1,但是由于此时发送方没有收到应答,于是可能重发了一个seq=0的分段,但是此时即将发送的一个 ...
sender重发一个seq = 0的segment,但是receiver不知道这个segment是新的还是旧的,即应该丢掉还是放到自己的receive queue里。
作者: eexplorer 发布时间: 2010-01-19
作者: jiufei19 发布时间: 2010-01-19
作者: jiufei19 发布时间: 2010-01-19
恩,就是这个意思,那么再请eexplorer看看我在13楼做的一个该问题的小结是否合理,谢谢!
> 如果网络速度非常高,则限制为32bit一半的序号空间的做法,虽然可以避免回绕带来的混淆问题,但是却会造成严重的吞吐量下降,
> 此时必须引入PAWS算法来避免序号的快速回绕
我始终觉得,引入2**31的限制只是在理论上做了一些限制,用来推导一些别的东西,如max window size的问题。
实际情况下:
1. 不可能有那么大的窗口
2. PAWS应该更常用
所以问题没这么严重。
不过佩服你的学习钻研精神,我也学到了不少东西。
作者: eexplorer 发布时间: 2010-01-19
另外,2**31一定不是随意想出来的数,肯定是在一个条件下得到的,我认为就是按照如下2点:
1、窗口大小是2的整数次幂
2、限制为2**32的一半,理论上肯定序号回绕肯定不会导致混淆问题出现,因为前后序号相差只能最大达到2**31,因此当回绕后,最早前一个窗口的序号已经越过了2**31,所以如果用刚才的例子seq=0,则此时该序号一定是新的数据了。不过这里一定要注意这样来保证序号回绕问题不会产生麻烦的代价就是吞吐量下降了,否则PAWS也没有必要引入
再次感谢eexplorer的热心哈,总是在我需要的时候你给出的解答能让我进一步理解,虽然有时不能完全彻底

作者: jiufei19 发布时间: 2010-01-19

1、参考图1
1、下面我们分析下对应2**32的序号空间,究竟发送和接收窗口需要多大?
a)我们首先假定滑动窗口大小刚好容纳整个32bits序号空间,于是表示当发送方没有是收到接收方的ACK之前,最多可以发送2**32字节数据
b)本图为初始连接的状态
c)假定发送方发送了2**32字节数据后,尚未收到接收方的任何ACK,于是发送方开始等待,也即snd.una=1(不失一般性,假定SYN分段序号为0)
d)因为已经发送了2**32字节数据,所以下一次发送的分段的序号将从0重新开始,并且我们假定在某个时刻发送方收到了接收方发回的ACK,该ACK确认了头1000个字节的数据,并且1001开始的部分分段可能正在途中(被delayed),我们不妨假定正好1001-2000的分段被延迟了,尚未到达接收方
e)因为发送方收到了ACK1000,于是发送方可以继续发送新的分段,这里一定要注意,发送方可以发送的新的数据量并不是只限1-1000这1千字节,因为究竟可以发送多大数据量取决于此ACK1000种所携带的窗口大小,而这个窗口大小又取决于接收方应用读取接收方TCP缓存的大小,显然这个读取的大小并不固定为1000字节,其实该大小和1000没有任何关系,完全是接收方应用的read行为,所以此时完全存在接收方应用所读的数据大于1000字节的情况,于是这个窗口的大小随ACK1000返回给发送方后,发送方此时就可能发送1001-2000开始的序号分段,那么问题就出现了,当新的1001分段发出后,将和老的1001分段序号完全相同,则接收方将如何判断哪个是old,哪个是new?另外,如果此时发送方因为超时而重发1-1000分段,那么同样因为接收方当前正准备接收1-1000分段,这样也造成了混淆,于是我们知道滑动窗口不可能和序号空间一样大
2、因为滑动窗口的大小必须是2的整数次幂,所以我们接下来分析是否可以为2**31
参考图2
a)上图显示了当滑动窗口为32bit序号空间一半的情况
b)同理按照刚才的分析,此时发送方在未收到接收方的ACK时,最多可以发送2**31字节数据,于是snd.una=1,此时发送方暂停发送
c)并且我们假定接收方全部正确收到了,于是我们有rcv.wup=2**31,接收窗口右边界=rcv.wup+rcv.wnd
d)因为发送方一直没有收到ACK,所以此时发送方可能超时然后重发认为丢失的那些分段,这些分段的序号从0-2**31-1不妨设为seq=0,那么问题就产生了,这个seq=0的分段对于接收方而言到底是old还是new?
e)显然接收方无法正确判断!!!注意,这里的关键问题都是因为下一个要接收的正确分段序号已经开始回绕了,导致重发的分段和新发分段的序号可能重叠,所以解决问题的办法只有是想法让下一个准备接收的分段序号不和重发的分段重叠,或者反过来即便要重叠,则必须通过PAWS那样引入另外的参数来区别
3、既然2**31不能为滑动窗口的最大值,那么只能考虑2**30了,于是
参考图3
接前面的分析,因为滑动窗口的大小只能是2的整数次幂,所以目前只能为2**30,这样,我们就很自然得到下面这个结论
rcv.wup+rcv.wnd – snd.una <= 2**31
此时因为下一个即将接收的分段序号没有到达32bit的最大值,所以不会出现回绕,则发送方此时只能是重发1-2**30内的序号分段,那么此时接收方就能轻易判断出此时发来的分段都是重复的old分段
通过上面分析,我们就可以自然得出window scale option的因子最大只能是14bit了
再次感谢eexplorer的热心帮助!
[ 本帖最后由 jiufei19 于 2010-1-20 12:14 编辑 ]
作者: jiufei19 发布时间: 2010-01-20
滑动窗口一定要是2的幂次方吗?
作者: hritian 发布时间: 2010-01-20
作者: jiufei19 发布时间: 2010-01-20
学习。
作者: 渣渣鸟 发布时间: 2010-01-23
好绕。
滑动窗口一定要是2的幂次方吗?
应该这么说,实际用的滑动窗口的大小并不一定是2^n。但是我们是在讨论最大允许的滑动窗口的大小,因为window scale option是一个shift count,
所以最大是64K << 16 = 2^32,接下来就是64K << 15 = 2 ^31...
而jiufei19的分析已经排除了2^32, 2^31两种情况。
我前面一直没完全同意jiufei19的结论也就是和你有一样的疑问,今天突然想到了原因

作者: eexplorer 发布时间: 2010-01-23
作者: jiufei19 发布时间: 2010-01-24
如果在一个MSL内发送了3.5G数据呢?接收方1G的窗口内还是可能有可能收到重发的序号为1的数据,照样分不清是新是旧.只要是快速的网络,必须引入时间戳才能解决问题.
2**31的问题参考 tcp/ip详解 卷2 24章,这些序号的比较是用补码来实现的,补码有一些很好的数学特性.
作者: kutong 发布时间: 2010-12-15
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28