时间戳选项发送方在每个报文段中放置一个时间戳值。接收方在确认中返回这个数值,从而允许发送方为每一个收到的ACK计算RTT(我们必须说“每一个收到的ACK”而不是“每一个收到的报文段”,是因为TCP通常用一个ACK来确认多个报文段)。我们提到过目前很多实现为每个窗口值计算一个RTT,对于包含8个报文段的窗口而言这是正确的。然而,较大的窗口大小则需要进行更好的RTT计算;
时间戳是一个单调递增的值。由于接收方只需要回显收到的内容,因此不需要关注时间戳单元是什么。这个选项不需要再两个主机之间进行任何形式的时钟同步。RFC1323推荐在1毫秒和1秒之间将时间戳的值增加1;
在连接建立阶段,对于这个选项的规定与扩大窗口选项类似。主动发起连接的一方在它的SYN选项中指定选项。只有在从另一方的SYN中收到这个选项后,该选项才会在以后的报文段中进行设置;
接收方TCP不需要对每个包含数据的报文段进行确认,许多实现每两个报文段发送一个ACK。如果接收方发送了一个确认了两个报文段的ACK,那么哪一个收到的时间戳应当放入回显应答字段中发回去呢?
为了减少任异端所维持的状态数量,对于每个连接只保持一个时间戳的数值,选择何时更新这个数值的算法非常简单:
(1) TCP跟踪下一个ACK中将要发送的时间戳值(tsrecent变量)以及最后发送的ACK中的确认序号(lastack变量)。这个序号就是接收方期望的序号;
(2) 当一个包含字节号lastack的报文段到达时,该报文段中的时间戳被保存在tsrecent中。
(3) 无论何时发送一个时间戳选项,tsrecent就作为时间戳回显应答字段被发送,而序号字段被保存在lastack中;
这个算法能够处理下面两种情况:
(1) 如果ACK被接收方延迟,则作为回显值的时间戳值应该对应于最早被确认的报文段。
例如:如果两个包含1-1024和1025-2048的的报文段到达,每一个都带有一个时间戳选项,接收方产生一个ACK2049来对它们进行确认。此时,ACK中的时间戳应该是包含字节1-1024的第一个报文段的时间戳。这种处理是正确的,因为发送方在进行重传超时时间的计算时,必须将延迟的ACK也考虑在内;
(2) 如果一个收到的报文段虽然在窗口范围内但同时又是失序,这就表明前面的报文段已经丢失。那个丢失的报文段到达时,它的时间戳(而不是失序的报文段的时间戳)将被回显。
例如:假定有3个各包含1024字节的报文段,按如下顺序接收:1-1024的报文段1,2049-3072的报文段2,1025-2048的报文段2。返回ACK应该是带有报文段1时间戳的ACK1025(一个正常期望的对数据的ACK),带有报文段1的时间戳的ACK1025(一个重复的,响应位于窗口内但却是失序的报文段的ACK),然后是带有报文段2的时间戳的ACK3037(不是报文段3中的时间戳)。这与当报文段丢失时的对RTT估算过高具有同样的效果,但这比估计过低要好些。而且,如果最后的ACK含有来自报文段3的时间戳,它可以包括重复的ACK返回和报文段2被重传所需的时间,或者可以包括发送方的报文段2的重传定时器到期时间。无论哪一种情况下,回显报文段3的时间戳都将引起发送方的RTT计算出现偏差;
时间戳除了能够更好的计算RTT,还为发送发提供了一种方法,以避免接收到旧的报文段,错误的以为它们是现在数据的一部分;
文章来自: <TCP/IP详解>