一、奇怪现象:
三次握手时,前两次syn|syn+ack中的window size明明很大,但是第三次握手的时候window size却突然变得很小,
并且后续的数据传输的过程中,window size仍然很小,和syn|syn+ack中的不符,对于我们初探tcp的学习者来说,
会一头雾水,其实是我们只关注了tcp的重要点,而没有了解到tcp的小细节。
二、tcp option:
tcp报文除了标准的20字节,其实还可以最大到达60字节,由HL(4位,最大15*32 / 8 = 60字节),多出来的字节是tcp option,
即tcp可选字段,格式为:
| type(1-byte) | length(1-byte) | values(length - 2 byte) |
而上面的奇怪现象是由于tcp在syn|syn+ack中使用了window scale factor这个可拓展值进行了拓展,
在该阶段(syn|syn+ack)的window size不受window scale factor影响,即window size是多少,那么就是多少,
但是后续的数据传输包括第三次握手的window size均要向左移动该window scale factor,
即window size * (2 ** scale_factor) or window size << scale_factor才是实际的window size
三、例子:
访问百度为例子:
sudo tcpdump -i eth0 host www.baidu.com -S -xx -n
12:15:02.145424 IP 172.18.192.125.36028 > 115.239.210.27.80: Flags [S], seq 4200731336, win 29200, options [mss 1460,sackOK,TS val 105544669 ecr 0,nop,wscale 7], length 0
0x0000: eeff ffff ffff 0016 3e08 b134 0800 4500
0x0010: 003c 6915 4000 4006 1f0c ac12 c07d 73ef
0x0020: d21b 8cbc 0050 fa62 12c8 0000 0000 a002
0x0030: 7210 b2c9 0000 0204 05b4 0402 080a 064a
0x0040: 7bdd 0000 0000 0103 0307
syn:
以太网报文:eeff ffff ffff 0016 3e08 b134 0800
ip报文:4500 003c 6915 4000 4006 1f0c ac12 c07d 73ef d21b
tcp报文:8cbc 0050 fa62 12c8 0000 0000 a002 7210 b2c9 0000 0204 05b4 0402 080a 064a 7bdd 0000 0000 0103 0307
a002中的a为HL(10个32位长度的头部),所以tcp头部40字节,标准20字节,所以多余的20字节为tcp option,
其中03 0307为window scale factor, 07为其值
0x7210=29200,为window size,此时不会受window scale factor的影响
12:15:02.172269 IP 115.239.210.27.80 > 172.18.192.125.36028: Flags [S.], seq 439811744, ack 4200731337, win 8192, options [mss 1452,sackOK,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,wscale 5], length 0
0x0000: 0016 3e08 b134 eeff ffff ffff 0800 4514
0x0010: 003c 6915 4000 3606 28f8 73ef d21b ac12
0x0020: c07d 0050 8cbc 1a36 fea0 fa62 12c9 a012
0x0030: 2000 c554 0000 0204 05ac 0402 0101 0101
0x0040: 0101 0101 0101 0103 0305
syn+ack:
以太网报文:0016 3e08 b134 eeff ffff ffff 0800
ip报文:4514 003c 6915 4000 3606 28f8 73ef d21b ac12 c07d
tcp报文:0050 8cbc 1a36 fea0 fa62 12c9 a012 2000 c554 0000 0204 05ac 0402 0101 0101 0101 0101 0101 0103 0305
a012中的a为HL(10个32位长度的头部),所以tcp头部40字节,标准20字节,所以多余的20字节为tcp option,
其中03 0305为window scale factor, 05为其值
0x2000=8192,为window size,此时不会受window scale factor的影响
12:15:02.172312 IP 172.18.192.125.36028 > 115.239.210.27.80: Flags [.], ack 439811745, win 229, length 0
0x0000: eeff ffff ffff 0016 3e08 b134 0800 4500
0x0010: 0028 6916 4000 4006 1f1f ac12 c07d 73ef
0x0020: d21b 8cbc 0050 fa62 12c9 1a36 fea1 5010
0x0030: 00e5 b2b5 0000
ack:
以太网报文:eeff ffff ffff 0016 3e08 b134 0800
ip报文:4500 0028 6916 4000 4006 1f1f ac12 c07d 73ef d21b
tcp报文:8cbc 0050 fa62 12c9 1a36 fea1 5010 00e5 b2b5 0000
5010中的5为HL,标准报文20字节,没有tcp option,
0x00e5=229,当前传输的window size为229,但是由于前面的syn中有window scale factor(7),
因此实际的窗口为229 << 7 = 29312,
另一个验证方式,因为syn的窗口为29200,在传输过程中,那么需要右移7位,29200 >> 7 = 228(上移一位),229
所以这就解释了为什么在syn的window size为什么是29200,而在后续的返送中才仅仅只有229这几百的window size,(同理syn+ack的情况)
其实是我们不了解有tcp option,里面有个tcp window scale factor这个东西