原文轉自:http://www.cnblogs.com/lovemyspring/articles/4271716.html
TCP應該是以太網協議族中被應用最為廣泛的協議之一,這里就聊一聊TCP協議中的TimeStamp選項。這個選項是由RFC 1323引入的,該C建議提交於1992年,到今天已經足足有20個年頭。不過相信大部分程序猿對這個建議還是相當陌生。
要理解為啥需要用TimeStamp選項,還需要從TCP協議的幾個基本設計說起。
TCP協議的幾個設計初衷,以及引發的問題:
1. 協議規定收端不需要響應每一個收到的數據報文,只需要收到N個報文后,向發端回復一個ack報文即可。
這樣的規定是為了提高通訊的效率,但是也引入了幾個問題:
A. 發端發出報文后,到底多久能夠收到ack是不確定的。
B. 萬一ack報文丟失了,判斷需要重發的timeout時間也很難確定。
2. TCP報文中,標示Sequence號的地址長度為32位。
這就限制了發端最多一次發送2^30長度的數據,就必須等待ack信號。為啥呢?在這個鏈接里有一些詳細的討論。
然而對於超高速以太網(1000M以至於10G),這樣會影響TCP連接的轉發效率。
為解決上面提到的問題,TimeStamp選項主要有兩個用途:
1. 測量TCP連接兩端通訊的延遲(Round Trip Time Measurement)
有了RTTM機制,TCP的兩端可以很容易的判斷出線路上報文的延遲情況,從而制定出一個優化的發包間隔和報文TimeOut時間,從而解決了第一個問題。
2. 處理Sequence號反轉的問題(Protect Against Wrapped Sequence Numbers)。
TCP收端收到一個數據報文后,會先比較本次收到報文的TimeStamp和上次收到報文的TimeStamp。如果本次的比較新,那么可以直接判斷本次收到的報文是新的報文,不需要進行復雜的Sequence Number Window Scale計算,從而解決了第二個問題。
然而,RFC1323建議還存在一些隱患。
建議中定義TimeStamp增加的間隔可以使1ms-1s。如果設備按照1ms的速度增加TimeStamp,那么只要一個TCP連接連續24.8天(1ms*2^31)沒有通訊,再發送報文,收端比較本次報文和上次報文TimeStamp的動作就會出錯。(問題1)
(注:TCP協議中並沒有定義KeepAlive。如果應用層代碼不定義超時機制,TCP連接就永遠不會中斷,所以連續24.8天不通訊的情況是卻有可能發生的。)
引用Linux相關代碼:((s32)(tp->rx_opt.rcv_tsval - tp->rx_opt.ts_recent) < 0)
比如 tp->rx_opt.rcv_tsval = 0x80000020, tp->rx_opt.ts_recent = 0x10
((s32)(tp->rx_opt.rcv_tsval - tp->rx_opt.ts_recent) = (s32)0x80000010,是一個負數,必然小於0。
如果解決問題1呢?
已知按照RFC1323的規定,按照最快TimeStamp增加的速度,也需要24.8天TImeStamp才有可能發生反轉。
如果((s32)(tp->rx_opt.rcv_tsval - tp->rx_opt.ts_recent) < 0)判斷成立,還可以再用本地收到報文的本地TimeStamp減去上一次收到報文的本地TimeStamp。如果時間大於24.8天,那么就是TimeStamp發生了反轉;否則就不是反轉的情況。這樣做是不是就萬無一失了呢?不一定!
別忘了本地TimeStamp的計數器也是個32位,也可能會翻轉的。(問題2)
舉個極端的例子:假設TCP兩端設備的TimeStamp增加間隔不一致,A為1ms,B為10ms。TCP連接連續248天沒有通訊;這個時候B向A發送了一個數據報文。
此時B發送給A的TCP報文中的TimeStamp,正好發生了翻轉。然而由於A的計數器是每1ms加一的,248天時間,A的計數器已經歸零過5次了。這時候再用本地TimeStamp做判斷還是錯的。
比較保險的做法是:
如果TCP連接的速度不那么快(2^32/s),本地TimeStamp用最大間隔時間1S。從而規避了(問題2)。
如果TCP連接速度非常快,1S的TimeStamp間隔就有些不合時宜了,可以選小一級,如100ms。如果這時候還會發生連續24800天(為啥是24800天呢)不通訊的情況,除了罵娘以外,我也沒辦法了。
原文轉自:http://blog.csdn.net/zhangskd/article/details/7195795
Description
Protocol suite: TCP/IP.
Protocol type: Transport layer protocol.
Option length: 10 bytes.
The TCP Timestamp option obsoletes the TCP Echo request and Echo reply options.
RFC 1323:
The timestamps are used for two distinct mechanisms: RTTM (Round Trip Time Measurement)
and PAWS (Protected Against Wrapped Squences).
結構圖

Kind. 8 bits. Set to 8.
Length. 8 bits. Set to 10.
Timestamp Value (TSval). 32 bits.
This field contains the current value of the timestamp clock of the TCP sending the option.
TImestamp Echo Reply (TSecr). 32 bits.
This field only valid if the ACK bit is set in the TCP header. If it is valid, it echos a timestamp value
that was sent by the remote TCP in the TSval field of a Timestamps option. When TSecr is not valid,
its value must be zero. The TSecr value will generally be from the most recent Timestamp option
that was received; however, there are exceptions that are explained below. A TCP may send the
Timestamp option in an initial SYN segment(i.e., segment containing a SYN bit and no ACK bit), and
may send a TSopt in other segments only if it received a TSopt in the initial SYN segment for the
connection.
Linux內核中的使用
如果支持Timestamp選項,那么可以用此選項來計算RTT。
- static void tcp_ack_saw_tstamp(struct sock *sk , int flag)
- {
- /* RTTM Rule: A TSecr value received in a segment is used to
- * update the averaged RTT measurement only if the segment
- * acknowledges some new data, i.e., only if it advances the
- * left edge of the send window.
- *
- * Changed: reset backoff as soon as we see the first valid
- * sample. If we do not, we get strongly overestimated rto.
- * With timestamps samples are accepted even from very
- * old segments: f.e., when rtt=1 increases to 8, we retransmit
- * 5 times and after 8 seconds delayed answer arrives rto
- * becomes 120 seconds!
- */
- struct tcp_sock *tp = tcp_sk(sk);
- tcp_valid_rtt_meas(sk, tcp_time_stamp - tp->rx_opt.rcv_tsecr);
- }
rtt即等於現在的時間tcp_time_stamp減去Timestamp Echo Reply,即tp->rx_opt.rcv_tsecr。
TCP timestamp option的作用:
1)allow more accurate round-trip time measurements for deriving the retransmission
timeout estimator.
2)protect against old segments from the previous incarnations of the TCP connection.
3)allow detection of unnecessary retransmissions.
