Skip to content

Commit 7d60a0e

Browse files
authored
Merge pull request #261 from youzi-2333/isn_deff
fix typo in `isn_deff`
2 parents 24a6969 + 7cb1203 commit 7d60a0e

File tree

1 file changed

+11
-11
lines changed

1 file changed

+11
-11
lines changed

network/3_tcp/isn_deff.md

+11-11
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44

55
**为什么 TCP 每次建立连接时,初始化序列号都要不一样呢?**
66

7-
接下来,我一步一步给大家讲明白,我觉得应该有不少人会有类似的问题,所以今天在肝一篇
7+
接下来,我一步一步给大家讲明白,我觉得应该有不少人会有类似的问题,所以今天再肝一篇
88

99
> 为什么 TCP 每次建立连接时,初始化序列号都要不一样呢?
1010
1111
主要原因是为了防止历史报文被下一个相同四元组的连接接收。
1212

1313
> TCP 四次挥手中的 TIME_WAIT 状态不是会持续 2 MSL 时长,历史报文不是早就在网络中消失了吗?
1414
15-
是的,如果能正常四次挥手,由于 TIME_WAIT 状态会持续 2 MSL 时长,历史报文会在下一个连接之前就会自然消失。
15+
是的,如果能正常四次挥手,由于 TIME_WAIT 状态会持续 2 MSL 时长,历史报文会在下一个连接之前就会自然消失。
1616

1717
但是来了,我们并不能保证每次连接都能通过四次挥手来正常关闭连接。
1818

@@ -44,10 +44,10 @@
4444

4545
> 那客户端和服务端的初始化序列号都是随机的,那还是有可能随机成一样的呀?
4646
47-
RFC793 提到初始化序列号 ISN 随机生成算法:ISN = M + F(localhost, localport, remotehost, remoteport)。
47+
RFC793 提到初始化序列号 ISN 随机生成算法:`ISN = M + F(localhost, localport, remotehost, remoteport)`
4848

4949
- M 是一个计时器,这个计时器每隔 4 微秒加 1。
50-
- F 是一个 Hash 算法,根据源 IP、目的 IP、源端口、目的端口生成一个随机数值,要保证 hash 算法不能被外部轻易推算得出。
50+
- F 是一个 Hash 算法,根据源 IP、目的 IP、源端口、目的端口生成一个随机数值,要保证 Hash 算法不能被外部轻易推算得出。
5151

5252
可以看到,随机数是会基于时钟计时器递增的,基本不可能会随机成一样的初始化序列号。
5353

@@ -66,11 +66,11 @@ RFC793 提到初始化序列号 ISN 随机生成算法:ISN = M + F(localhost,
6666

6767
通过前面我们知道,**序列号和初始化序列号并不是无限递增的,会发生回绕为初始值的情况,这意味着无法根据序列号来判断新老数据**
6868

69-
不要以为序列号的上限值是 4GB,就以为很大,很难发生回绕。在一个速度足够快的网络中传输大量数据时,序列号的回绕时间就会变短。如果序列号回绕的时间极短,我们就会再次面临之前延迟的报文抵达后序列号依然有效的问题。
69+
不要以为序列号的上限值是 4 GB,就以为很大,很难发生回绕。在一个速度足够快的网络中传输大量数据时,序列号的回绕时间就会变短。如果序列号回绕的时间极短,我们就会再次面临之前延迟的报文抵达后序列号依然有效的问题。
7070

71-
为了解决这个问题,就需要有 TCP 时间戳。tcp_timestamps 参数是默认开启的,开启了 tcp_timestamps 参数,TCP 头部就会使用时间戳选项,它有两个好处,**一个是便于精确计算 RTT,另一个是能防止序列号回绕(PAWS)**
71+
为了解决这个问题,就需要有 TCP 时间戳。`tcp_timestamps` 参数是默认开启的,开启了 `tcp_timestamps` 参数,TCP 头部就会使用时间戳选项,它有两个好处,**一个是便于精确计算 RTT,另一个是能防止序列号回绕(PAWS)**
7272

73-
试看下面的示例,假设 TCP 的发送窗口是 1 GB,并且使用了时间戳选项,发送方会为每个 TCP 报文分配时间戳数值,我们假设每个报文时间加 1,然后使用这个连接传输一个 6GB 大小的数据流。
73+
试看下面的示例,假设 TCP 的发送窗口是 1 GB,并且使用了时间戳选项,发送方会为每个 TCP 报文分配时间戳数值,我们假设每个报文时间加 1,然后使用这个连接传输一个 6 GB 大小的数据流。
7474

7575
![图片](https://img-blog.csdnimg.cn/img_convert/1d497c38621ebc44ee3d8763fd03da67.png)
7676

@@ -92,8 +92,8 @@ RFC793 提到初始化序列号 ISN 随机生成算法:ISN = M + F(localhost,
9292

9393
Linux 以本地时钟计数(jiffies)作为时间戳的值,不同的增长时间会有不同的问题:
9494

95-
- 如果时钟计数加 1 需要 1ms,则需要约 24.8 天才能回绕一半,只要报文的生存时间小于这个值的话判断新旧数据就不会出错。
96-
- 如果时钟计数提高到 1us 加 1,则回绕需要约 71.58 分钟才能回绕,这时问题也不大,因为网络中旧报文几乎不可能生存超过 70 分钟,只是如果 70 分钟没有报文收发则会有一个包越过 PAWS(这种情况会比较多见,相比之下 24 天没有数据传输的 TCP 连接少之又少),但除非这个包碰巧是序列号回绕的旧数据包而被放入接收队列(太巧了吧),否则也不会有问题;
95+
- 如果时钟计数加 1 需要 1 ms,则需要约 24.8 天才能回绕一半,只要报文的生存时间小于这个值的话判断新旧数据就不会出错。
96+
- 如果时钟计数提高到 1 us 加 1,则回绕需要约 71.58 分钟才能回绕,这时问题也不大,因为网络中旧报文几乎不可能生存超过 70 分钟,只是如果 70 分钟没有报文收发则会有一个包越过 PAWS(这种情况会比较多见,相比之下 24 天没有数据传输的 TCP 连接少之又少),但除非这个包碰巧是序列号回绕的旧数据包而被放入接收队列(太巧了吧),否则也不会有问题;
9797
- 如果时钟计数提高到 0.1 us 加 1 回绕需要 7 分钟多一点,这时就可能会有问题了,连接如果 7 分钟没有数据收发就会有一个报文越过 PAWS,对于 TCP 连接而言这么短的时间内没有数据交互太常见了吧!这样的话会频繁有包越过 PAWS 检查,从而使得旧包混入数据中的概率大大增加;
9898

9999
Linux 在 PAWS 检查做了一个特殊处理,如果一个 TCP 连接连续 24 天不收发数据则在接收第一个包时基于时间戳的 PAWS 会失效,也就是可以 PAWS 函数会放过这个特殊的情况,认为是合法的,可以接收该数据包。
@@ -104,7 +104,7 @@ static inline bool tcp_paws_check(const struct tcp_options_received *rx_opt, int
104104
{
105105
......
106106

107-
//从上次收到包到现在经历的时间多于 24 天,返回 true
107+
// 从上次收到包到现在经历的时间多于 24 天,返回 true
108108
if (unlikely(get_seconds() >= rx_opt->ts_recent_stamp + TCP_PAWS_24DAYS))
109109
return true;
110110

@@ -115,7 +115,7 @@ static inline bool tcp_paws_check(const struct tcp_options_received *rx_opt, int
115115
116116
要解决时间戳回绕的问题,可以考虑以下解决方案:
117117
118-
1)增加时间戳的大小,由 32 bit 扩大到 64bit
118+
1)增加时间戳的大小,由 32 bit 扩大到 64 bit
119119
120120
这样虽然可以在能够预见的未来解决时间戳回绕的问题,但会导致新旧协议兼容性问题,像现在的 IPv4 与 IPv6 一样
121121

0 commit comments

Comments
 (0)