TCP序列号回绕问题

我求求你们能别抄来抄去的吗?每次搜个问题全是重复的博客!

参考:

  • http://m.blog.chinaunix.net/uid-24683784-id-5746959.html
  • https://docs.microsoft.com/en-us/troubleshoot/windows-server/networking/description-tcp-features

简介

这篇笔记记录了TCP如何处理序列号回绕问题。

措施

主要有两种措施用于解决序列号回绕问题:

  • 限制TCP窗口大小
  • 时间戳机制

限制TCP窗口大小

处理回绕问题的关键在于,在回绕发生时,如何判断两个序列号的先后关系

在内核中,判断先后关系的代码如下:(代码在Linux源码的include/net/tcp.h)

   266 /*
   267  * The next routines deal with comparing 32 bit unsigned ints
   268  * and worry about wraparound (automatic with unsigned arithmetic).
   269  */
   270 
   271 static inline bool before(__u32 seq1, __u32 seq2)
   272 {
   273         return (__s32)(seq1-seq2) < 0;
   274 }
   275 #define after(seq2, seq1)   before(seq1, seq2)

可以看到,内核中判断两个序列号的先后关系实现得非常简单,相减然后强转成有符号32位整数,然后判断是否小于0即可。

通过一个例子来看这个方法的正确性,TCP序列号是一个32位无符号整数,范围是[0, 4294967295],现在假设要比较两个序列号:

  • seq1 = 4294967295
  • seq2 = 4294967296,超过了可表示的范围,回绕为0

调用before(seq1, seq2)时,seq1-seq2的结果是4294967295,然后强制转换成有符号整数,4294967295 转换成了-1,小于0,于是函数输出seq1在seq2前面,这和真实情况一致。

不过这种比较是有条件的,例如,仍然取:

  • seq1 = 4294967295
  • seq2 = 4294967296 + 4294967294,超过了可表示的范围,回绕为4294967294

这次before(seq1,seq2)返回的结果就与事实不符了。

上面的算法能使用的前提是:回绕的范围不能太大。

准确地说,回绕的范围不能超过2**31,或者说,回绕之后的值,一定要小于2**31

那这个前提在TCP里面能满足吗?

可以!TCP窗口的最大值是1GB = 2**30 B < 2**31 B 所以使用上面的算法在实际情况中能够解决TCP的回绕问题,正确地区分出哪个序列号在前,哪个在后。

时间戳机制

理论上来说,上面的算法可以区分两个序列号,但是实际上可能出现这样的情况:

  • 客户端发送了一个包A给服务器,序列号范围在[seq1, seq2]之间

  • 由于网络原因,这个包A过了很久都没有到达服务器

  • 服务器流量很大,序列号回绕了一次,序列号范围又回到了[seq1, seq2]

  • 包A历经千辛万苦终于到达服务器

  • 问题来了:这个包A是当前的有效包?还是回绕之前的包?

这个问题可以使用时间戳来解决,通过判断报文段的时间戳,可以判断报文段是否是过时的。

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值