一、常用tcp options
TCP协议头:
下面简单介绍TCP OPTIONS,长度不定,但长度必须以是32bits的整数倍。常见的选项包括MSS、SACK、Timestamp等等,最初的TCP只定义了扩展头部结尾(EOL), 没有扩展头部(NOP),最大分段长度(MSS), 其他字段都是后期扩展的. 每一个扩展头部必须在一开始包含1Byte的类型说明和1Byte的长度说明.扩展头部结尾(EOL)的出现纯属是因为TCP报文必须32Bit对齐.
如下表:
1.EOL 字段
格式:
用EOL代表TCP选项列表字段的结束,是所以TCP选项的结束而不是每一个选项后都要加EOL。
使用情况:只有选项列表结束后没有与TCP header length所标注大小相同时使用。因此也不一定放在tcp头部的末尾.举个例子,假如Header Length指定的TCP头长为40bytes,其中第29-38bytes为TSOPT选项,则可以在第39byte处添加一个EOL选项指示选项列表结束,可以看到EOL并没有位于TCP头的结束位置的第40byte。对于最后一个byte RFC793协议规定需要以0来填充。注意这个EOL后面填充的0已经不属于TCP选项的一部分了。
2.NOP 字段
主要是用来补充其他选项对齐。可以用在其他选项之间,或者结尾。比如为了使3字节的WSOPT选项4字节对齐,在选项开始添加一个NOP选项填充。但是发送端斌并不保证对齐。
3.MSS字段
TCP期待从对端收到的最大报文长度。也是对端可以发送的报文长度,仅指TCP数据,不包含TCP和ip头部,双方在各自的SYN包中描述自己希望的MSS大小, 如果没有描述, 则默认为536Byte,
MSS代表的是TCP的负载数据的大小。RFC6691明确规定在MSS选项中传递的MSS值为MTU减去IP基本头(ipv4为20bytes,IPV6为40bytes)和TCP基本头(20bytes)的值,不考虑扩展头。发送端负责发送数据前在这个MSS值的基础上扣除扩展头长度得出真实传输数据的长度。
MSS 不是一种协商, 而是一种自己的上限, 自己不会再接受比MSS更大的报文。
4.WSOPT (最大可扩展14bit, 和原有的窗口拼接可以达到2^30Byte, 约为1GB)
我们在介绍TCP头结构的时候提到过Window Size字段,这个字段占16位,最大为2^16-1,在长肥管道中,当发送端TCP需要通告更大的接收窗口的时候,就需要通过WSOPT选项了。当使用WSOPT选项的时候,接收窗口的实际大小则为Window Size<<shift.cnt,其中shift.cnt按照协议最大只能为14,当接收端接收到的shift.cnt大于14的时候,则按照14来处理Window Size。
WSOPT选项只能在SYN包中发送,因此当TCP连接建立起来后,window scale就固定了。一般在TCP实现上会有一个最大接收缓存,进而决定了最大接收窗口和window scale。WSOPT选项将原有的16位Window Size扩展到近30位大小(大约1GB)可以有效提升TCP允许使用的接收缓存,进而提升长肥网络的性能。
如果要使能window scale,需要发送端在SYN包中发送WSOPT选项,接收端在SYN-ACK包中同样发送WSOPT。注意协商window scale过程中协议要求不能对SYN和SYN-ACK报文头中的window size应用WSopt选项。WSOPT中的shift.cnt可以为0,标识window scale factor为1(即2^0=1),即接收窗口的实际大小即为Window Size。如果发送端发送了WSOPT选项但是没有收到对端的WSOPT选项,则需要将自己的window scale factor设置为1。
发送端和接收端都各有一个接收窗口和一个发送窗口,因此总共四个窗口,共维护4个scale factor。假设发送端接收窗口的scale factor为R,发送窗口的scale factor为S,则对应的接收端的接收窗口scale factor为R,发送窗口scale factor为S。在协商好两端的scale factor后,之后接收到的数据包中的Window Size字段自动进行scale factor,发送出去的数据包中的这个字段则为实际接收窗口右移scale factor后的结果。
5.SACK
选择性确认功能有助于提升TCP传输的效率.双方会在握手时提供自己是否支持SACK的选项.每一个SACK会占用一对32bit空间, 因此会总共占用(2 + 8 * n)个字节, 扩展头部一般最多放3个选择确认区间.(假定现代TCP会通常使用Timestamp特性)
6.时间戳选项
每一个报文可以携带当前的时间戳, 当得到一个往返信息时, 节点可以计算最新的RTT.
因为常规的TCP连接对于一个窗口只会计算一次RTT, 使用时间戳选项后, TCP连接可以获得更加细粒度的RTT计算
时间戳的另外一个作用是防止先前的报文干扰,不常见的是, 时间戳还可以作为Seq序号的辅助. 考虑当一个大带宽传输时, Seq序号只有32位, 记录4GB大小的内容, 可能某个内容正在网络传输时, 下一个相同的Seq序号的报文也同时到达, 对方节点可以根据Timestamp作为区分的一个参考依据.
Timestamp不需要双方同步, 只要将自己的Timestamp单项递增即可
7.UTO User Timeout Option 用户超时选项
这个选项指定了超过多长时间没有数据发送就关闭连接. 遵循如下公式:
实际超时时间 = min(本地系统最大超时时间, max( 本端宣告UTO, 远端宣告UTO, 最小超时时间))
8.TCP 认证选项
这个选项携带的是报文经过加密后的hash计算结果, 其并不包含预分发密钥, 因此应用需要自己解决如何生成共识密钥的过程, 这个认证选项只能作为判断报文是否被修改的一个依据.
9.路径MTU探测
根据SYN时互相提供的MTU或者默认值作为发送参数后, (由于路由的变化)双方可以根据连接过程中产生的ICMP报文来动态缩小MSS. 如果缩小后一定时间没有继续缩小, 可以逐渐增长.
但是防火墙阻挡或者某些主机不回应ICMP报文, 会引发TCP的black hole效应, 一个解决方法是TCP发现这种情况时尝试主动做小报文片段.
10.RST刺客
如上图所示, 当四次挥手已经顺利完成, Client已经进入TIME_WAIT阶段等待2MSL的时候, 此时Server发来一个之前的报文, Client进行ACK确认, 但是由于Server已经释放了链接, 并不能理解这个ACK报文, 因此发回来一个RST报文, 当Client收到RST的时候, TIME_WAIT阶段被强制终止。
系统常见的解决方法是: 在TIME_WAIT阶段不会应答任何RST报文
11.Server上的TCP
连接排队
系统为每一个TCP的端口提供了两个队列
- 向上层递交的队列: 如果应用层不能及时处理这些连接, 那么这些连接就会在队列中排队保存
- 三次握手未完成的队列: 如果系统不能及时处理, 或者1中的队列已满, 那么系统可能会将这些半连接保存成队列, 也有可能直接发送RST拒绝服务.
应用只有当连接建立完成之后才能知道服务的对象是谁, 因此在连接建立完成之前没有权利去拒绝服务,只有在建立完成后才能FIN或者RST
参考: