TCP建立连接时,为什么每次的SYN都不一样

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

    • 主要原因是为了防止历史报文被下一个相同四元组的连接接收。

  • TCP 四次挥手中的 TIME_WAIT 状态不是会持续 2 MSL 时长,历史报文不是早就在网络中消失了吗?

    • 是的,如果能正常四次挥手,由于 TIME_WAIT 状态会持续 2 MSL 时长,历史报文会在下一个连接之前就会自然消失。

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

    • 过程如下:

      • 客户端和服务端建立一个 TCP 连接,在客户端发送数据包被网络阻塞了,然后超时重传了这个数据包,而此时服务端设备断电重启了,之前与客户端建立的连接就消失了,于是在收到客户端的数据包的时候就会发送 RST 报文。

      • 紧接着,客户端又与服务端建立了与上一个连接相同四元组的连接;

      • 在新连接建立完成后,上一个连接中被网络阻塞的数据包正好抵达了服务端,刚好该数据包的序列号正好是在服务端的接收窗口内,所以该数据包会被服务端正常接收,就会造成数据错乱。

    • 如果每次建立连接,客户端和服务端的初始化序列号都是一样的话,很容易出现历史报文被下一个相同四元组的连接接收的问题。

  • 客户端和服务端的初始化序列号不一样不是也会发生这样的事情吗?

    • 是的,即使客户端和服务端的初始化序列号不一样,也会存在收到历史报文的可能。

    • 历史报文能否被对方接收,还要看该历史报文的序列号是否正好在对方接收窗口内,如果不在就会丢弃,如果在才会接收。

    • 如果每次建立连接客户端和服务端的初始化序列号都「不一样」,就有大概率因为历史报文的序列号「不在」对方接收窗口,从而很大程度上避免了历史报文

    • 每次初始化序列号不一样能够很大程度上避免历史报文被下一个相同四元组的连接接收,注意是很大程度上,并不是完全避免了。

  • 那客户端和服务端的初始化序列号都是随机的,那还是有可能随机成一样的呀?

    • RFC793 提到初始化序列号 ISN 随机生成算法:ISN = M + F(localhost, localport, remotehost, remoteport)。

      • M是一个计时器,这个计时器每隔 4 微秒加1。

      • F 是一个 Hash 算法,根据源IP、目的IP、源端口、目的端口生成一个随机数值,要保证 hash 算法不能被外部轻易推算得出。

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

  • 客户端和服务端初始化序列号都是随机生成的话,就能避免连接接收历史报文了。

    • 是的,但是也不是完全避免了。

    • 序列号(SEQ)和初始序列号(ISN)。

      • 序列号,是 TCP 一个头部字段,标识了 TCP 发送端到 TCP 接收端的数据流的一个字节,因为 TCP 是面向字节流的可靠协议,为了保证消息的顺序性和可靠性,TCP 为每个传输方向上的每个字节都赋予了一个编号,以便于传输成功后确认、丢失后重传以及在接收端保证不会乱序。序列号是一个 32 位的无符号数,因此在到达 4G 之后再循环回到 0。

      • 初始序列号,在 TCP 建立连接的时候,客户端和服务端都会各自生成一个初始序列号,它是基于时钟生成的一个随机数,来保证每个连接都拥有不同的初始序列号。初始化序列号可被视为一个 32 位的计数器,该计数器的数值每 4 微秒加 1,循环一次需要 4.55 小时。

    • 序列号和初始化序列号并不是无限递增的,会发生回绕为初始值的情况,这意味着无法根据序列号来判断新老数据。

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

    • 如果发现收到的数据包中时间戳不是递增的,则表示该数据包是过期的,就会直接丢弃这个数据包。

  • 客户端和服务端的初始化序列号都是随机生成,能很大程度上避免历史报文被下一个相同四元组的连接接收,然后又引入时间戳的机制,从而完全避免了历史报文被接收的问题。

  • 如果时间戳也回绕了怎么办?

    • 时间戳的大小是 32 bit,所以理论上也是有回绕的可能性的。

    • 时间戳回绕的速度只与对端主机时钟频率有关。

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

    • 要解决时间戳回绕的问题,可以考虑以下解决方案:

      • 增加时间戳的大小,由32 bit扩大到64bit

        • 导致新旧协议兼容性问题,像现在的IPv4与IPv6一样

      • 将一个与时钟频率无关的值作为时间戳,时钟频率可以增加但时间戳的增速不变

        • 随着时钟频率的提高,TCP在相同时间内能够收发的包也会越来越多。如果时间戳的增速不变,则会有越来越多的报文使用相同的时间戳。这种趋势到达一定程度则时间戳就会失去意义

  • 12
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值