8.3 时间戳(Time Stamp)选项

TCP时间戳选项用于解决通信延迟RTT测量、序列号快速回绕和SYN Cookie选项信息问题。通过时间戳,TCP能更准确测量RTT,实现PAWS防止序列号回绕,并在SYN Cookie中编码选项信息。然而,随着硬件时钟频率提升,时间戳回绕问题加剧,提出了扩大时间戳大小或使用与时钟频率无关的时间戳值等解决方案。
摘要由CSDN通过智能技术生成

  在时间戳选项诞生之前,TCP有三个问题难以解决:

(1)通信延迟RTT(Round Trip Time)测量

   RTT对于拥塞控制是十分重要的(比如计算多长时间重传数据)。通常,测量RTT的方法是发送一个报文,记录发送时间t1;当收到这个报文的确认时记录时间t2,t2 - t1就可以得到RTT。但TCP使用延迟确认机制,而且ACK可能会丢失,使得收到ACK时也无法确定是对哪个报文的回应。

(2)序列号快速回绕

  TCP判断数据是新是旧的方法是检查数据的序列号是否位于sun.una到sun.una + 2**31的范围内,而序列号空间的总大小为2*32,即约4.29G。在万兆局域网中,4.29G字节数据回绕只需几秒钟,这时TCP就无法准确判断数据的新旧。

(3)SYN Cookie的选项信息

  TCP开启SYN Cookie功能时由于Server在收到SYN请求后不保存连接,故SYN包中携带的选项(WScale、SACK)无法保存,当SYN Cookie验证通过、新连接建立之后,这些选项都无法开启。

  使用时间戳选项就可以解决上述问题。

  问题(1)解决方法:发送一个报文时将发送时间写入时间戳选项,在收到的ACK报文时通过其时间戳选项的回显值就能知道它确认的是什么时候发送的报文,用当前时间减去回显时间就可以得到一个RTT。

  问题(2)解决方法:收到一个报文时记录选项中的时间戳值,收到下一个报文时将其中的时间戳与上次的进行对比即可。时间戳回绕的速度只与对端主机时钟频率有关。Linux以本地时钟计数(jiffies)作为时间戳的值,假设时钟计数加1需要1ms,则需要约24.8天才能回绕一半,只要报文的生存时间小于这个值的话判断新旧数据就不会出错,这个功能被称为PAWS(Protect Against Wrapped Sequence numbers)。这样虽然可以解决问题(2),但随着硬件时钟频率的提升,时间戳回绕的速度也会加快,用时间戳解决序列号回绕问题的方法早晚会遇到困境。

  问题(3)解决方法:将WScale和SACK选项信息编码进32 bit的时间戳值中,建立连接时会收到ACK报文,将报文的时间戳选项的回显信息解码就可以还原WScale和SACK信息(这部分内容见《3.6 SYN Cookie》)。

  时间戳选项格式:

  其中,TSval是本端填写的时间戳,TSecr是回显给对端的时间戳。两端必须都分别在SYN包和SYN|ACK包中开启时间戳选项,时间戳功能才能生效。

  SYN包的时间戳选项在tcp_transmit_skb调用tcp_syn_options函数时设置:

 498 static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
 499                 struct tcp_out_options *opts,
 500                 struct tcp_md5sig_key **md5)
 501 {                      
 502     struct tcp_sock *tp = tcp_sk(sk);
 503     unsigned int remaining = MAX_TCP_OPTION_SPACE;
 504     struct tcp_fastopen_request *fastopen = tp->fastopen_req;
 505 
 506 #ifdef CONFIG_TCP_MD5SIG
 507     *md5 = tp->af_specific->md5_lookup(sk, sk);
 508     if (*md5) {
 509         opts->options |= OPTION_MD5;
 510         remaining -= TCPOLEN_MD5SIG_ALIGNED;
 511     }
 512 #else
 513     *md5 = NULL;
 514 #endif
...
 528     if (likely(sysctl_tcp_timestamps && *md5 == NULL)) {   //开启MD5选项就不能使用时间戳,why?
 529         opts->options |= OPTION_TS;
 530         opts->tsval 
时间戳timestamp)是指从某个固定时间(通常为1970年1月1日午夜)开始所经过的秒数。在Python中,可以使用time模块来获取和操作时间戳。 要获取当前的时间戳,可以使用time模块的time()函数,它返回当前时间的时间戳。例如: ```python import time timestamp = time.time() print(timestamp) ``` 要将时间戳转换为日期和时间,可以使用time模块的gmtime()或localtime()函数。gmtime()函数将时间戳转换为格林威治标准时间(GMT)的日期和时间,而localtime()函数将时间戳转换为本地时区的日期和时间。这两个函数返回一个包含年、月、日、小时、分钟等信息的time.struct_time对象。 ```python import time timestamp = 1630039812.123456 gm_time = time.gmtime(timestamp) local_time = time.localtime(timestamp) print(gm_time) print(local_time) ``` 要格式化日期和时间,可以使用time模块的strftime()函数。该函数接受一个格式化字符串作为参数,并根据其指令将时间转换为特定格式的字符串。以下是一些常见的指令: - %Y:四位数的年份 - %m:两位数的月份(01~12) - %d:两位数的日期(01~31) - %H:24小时制的小时数(00~23) - %M:分钟数(00~59) - %S:秒数(00~59) ```python import time timestamp = 1630039812.123456 formatted_time = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(timestamp)) print(formatted_time) ``` 关于时区(timezone),Python中的time模块默认使用本地时区。如果需要处理不同时区的时间,可以使用datetime模块中的相关函数和类。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值