HelloBug0

1 什么是TCP序列号?

TCP序列号是TCP包头中的一个字段,如下图: TCP首部格式

TCP序列号是一个32位的无符号整数,用于为传输的每个字节(TCP载荷=TCP层携带的应用层数据)进行编号,确保接收方收到多个TCP报文之后,对TCP载荷进行正确重组、识别重复或者丢失的TCP包,另外,接收方通过ACK回复已经收到的序列号,实现收发两端的可靠传输。

不同TCP连接之间的序列号相互独立,互不相关。每次建立一个TCP连接时,操作系统随机产生一个ISN(Initial Sequence Number,初始序列号),之后每发送一个字节的应用层数据,序列号加1。在发送包含SYN、FIN标志的包时,也会消耗一个序列号,因为SYN包或FIN包用于建立连接和终止连接,需要像数据一样被可靠的确认。

序列号的最大值为 2^32-1 ,在10Gbps网络中最多需要约3.44秒消耗完,然后从0开始。

2 序列号用完了怎么办?

序列号用完了,会重新从0开始,称之为序列号回绕。

3 序列号回绕可能有什么问题?

在高速网络中,序列号在很短的时间内正常飞快,序列号回绕可能导致接收端错误识别新旧数据包。

假如当前发送的TCP包的序列号是4,294,967,290(2^32-1=4,294,967,295),下一个包的TCP包的序列号是4,200,967,290(注意此时发生了序列号回绕),如果此时一个序列号为4,294,967,200的旧包到达了接收端,因为这个序列号比接受端收到的序列号大,接收端可能认为这是一个新包,而之后到达的新包被接收端丢弃。

4 序列号回绕如何解决?

TCP首部中有选项字段,在发送TCP数据包的时候,增加时间戳选项,如果收到的数据包里的序列号更大,比较当前收到的数据包里的时间戳和之前收到的数据包里的时间戳,判断数据包是更新还是更旧。

这种处理机制称作 Per-host PAWS(Protection Against Wrapped Sequence numbers),即连接级别的序列号回绕保护机制。

PAWS中通过TCP四元组(源IP、源端口、目的IP、目的端口)识别一个TCP连接。

5 如何开启时间戳选项?

通过配置内核参数 net.ipv4.tcp_timestamps = 1 开启时间戳选项,在TCP连接建立过程中,只有当客户端和服务端都支持时间戳选项的时候才会在后续的包中继续使用该选项。

6 TCP首部中的时间戳选项是什么样的?

时间戳选项类型为8,总长度为10个字节,包含两个时间戳,每个时间戳占4个字节,第一个时间戳表示发送该包时的时间戳,第二个时间戳表示最近收到的TCP数据包里的第一个时间戳。

时间戳使用32位无符号整数表示系统启动以来的时间,单位和CPU频率有关,如果CPU频率是1KHZ,则单位是1毫秒,如果CPU频率是1MHz,则单位是1微秒。

时间戳的最大值为 2^32-1,如果单位是1毫秒,则经过49.7天重新从0开始,如果单位是1微秒,则经过71.6分钟重新从0开始。和序列号回绕相似,也可以称之为时间戳回绕。

TCP首部中的时间戳选项示例如下: 时间戳选项

7 时间戳回绕有什么影响?

时间戳回绕对所有的TCP连接都有影响,如果发生时间戳回绕,PAWS机制会判断新到包的时间戳和之前收到的包的时间戳是否超过合理阈值,如果在合理阈值内,比如从很大变成很小,则处理这个包,否则将这个包丢弃。