1. 前言
TCP通信時,如果發送序列中間某個數據包丟失,TCP會通過重傳確認的包開始的后續包,這樣原先已經正確傳輸的包也可能重復發送,急劇降低了TCP性能。為改善這種情況,發展出SACK(Selective Acknowledgment, 選擇性確認)技術,使TCP只重新發送丟失的包,不用發送后續所有的包,而且提供相應機制使接收方能告訴發送方哪些數據丟失,哪些數據重發了,哪些數 據已經提前收到等。
2. SACK選項
SACK信息是通過TCP頭的選項部分提供的,信息分兩種,一種標識是否支持SACK,是在TCP握手時發送;另一種是具體的SACK信息。
2.1 SACK允許選項
類型值: 4
+---------+---------+
| Kind=4 | Length=2|
+---------+---------+
| Kind=4 | Length=2|
+---------+---------+
該選項只允許在有SYN標志的TCP包中,也即TCP握手的前兩個包中,分別表示各自是否支持SACK。
2.2 SACK選項
選項類型: 5
選項長度: 可變,但整個TCP選項長度不超過40字節,實際多不超過4組邊界值。
+--------+--------+
| Kind=5 | Length |
+--------+--------+--------+--------+
| Left Edge of 1st Block |
+--------+--------+--------+--------+
| Right Edge of 1st Block |
+--------+--------+--------+--------+
| |
/ . . . /
| |
+--------+--------+--------+--------+
| Left Edge of nth Block |
+--------+--------+--------+--------+
| Right Edge of nth Block |
+--------+--------+--------+--------+
| Kind=5 | Length |
+--------+--------+--------+--------+
| Left Edge of 1st Block |
+--------+--------+--------+--------+
| Right Edge of 1st Block |
+--------+--------+--------+--------+
| |
/ . . . /
| |
+--------+--------+--------+--------+
| Left Edge of nth Block |
+--------+--------+--------+--------+
| Right Edge of nth Block |
+--------+--------+--------+--------+
該選項參數告訴對方已經接收到并緩存的不連續的數據塊,注意都是已經接收的,發送方可根據此信息檢查究竟是哪個塊丟失,從而發送相應的數據塊。
* Left Edge of Block
不連續塊的個數據的序列號
* Right Edge of Block
不連續塊的一個數據的序列號之后的序列號。
表示(Left Edge - 1)和(Right Edge)處序列號的數據沒能接收到。
3. SACK的產生
SACK通常都是由TCP接收方產生的,在TCP握手時如果接收到對方的SACK允許選項同時自己也支持SACK的話,在接收異常時就可以發送SACK包通知發送方。
3.1 對中間有丟包或延遲時的SACK
如果TCP接收方接收到非期待序列號的數據塊時,如果該塊的序列號小于期待的序列號,說明是網絡復制或重發的包,可以丟棄;如果收到的數據塊序列號大于期待的序列號,說明中間包被丟棄或延遲,此時可以發送SACK通知發送方出現了網絡丟包。
為反映接收方的接收緩存和網絡傳輸情況,SACK中的個塊必須描述是那個數據塊激發此SACK選項的,接收方應該盡可能地在SACK選項部分中填寫盡可能多的塊信息,即使空間有限不能全部寫完,SACK選項中要報告近接收的不連續數據塊,讓發送方能了解當前網絡傳輸情況的信息。
3.2 對重發包的SACK(D-SACK)
RFC2883中對SACK進行了擴展,在SACK中描述的是收到的數據段,這些數據段可以是正常的,也可能是重復發送的,SACK字段具有描述重復發送的數據段的能力,在塊SACK數據中描述重復接收的不連續數據塊的序列號參數,其他SACK數據則描述其他正常接收到的不連續數據,因此塊SACK描述的序列號會比后面的SACK描述的序列號大;而在接收到不完整的數據段的情況下,SACK范圍甚至可能小于當前的ACK值。通過這種方法,發送方可以更仔細判斷出當前網絡的傳輸情況,可以發現數據段被網絡復制、錯誤重傳、ACK丟失引起的重傳、重傳超時等異常的網絡狀況。
4. 發送方對SACK的響應
TCP發送方都應該維護一個未確認的重發送數據隊列,數據未被確認前是不能釋放的,這個從重發送隊列中的每個數據塊都有一個標志位“SACKed”標識是否該塊被SACK過,對于已經被SACK過的塊,在重新發送數據時將被跳過。發送方接收到接收方SACK信息后,根據SACK中數據標志重發送隊列中相應的數據塊的“SACKed”標志,但如果接收不到接收方數據,超時后,所有重發送隊列中數據塊的SACKed位都要清除,因為可能接收方已經出現了異常。
5. SACK應用舉例
發送方發 接收方接 接收方發送的ACK
送的數據 收的數據 (包括SACK)
5.1 SACK累加接收的數據
5000-5499 (該包丟失)
5500-5999 5500-5999 5000, SACK=5500-6000
6000-6499 6000-6499 5000, SACK=5500-6500
6500-6999 6500-6999 5000, SACK=5500-7000
7000-7499 7000-7499 5000, SACK=5500-7500
5.2 數據包丟失,ACK丟失
3000-3499 3000-3499 3500 (ACK包丟失)
3500-3999 3500-3999 4000 (ACK包丟失)
4000-4499 (該包丟失)
4500-4999 4500-4999 4000, SACK=4500-5000 (ACK包丟失)
3000-3499 3000-3499 4000, SACK=3000-3500, 4500-5000
---------此為D-SACK
5.3 數據段丟失和延遲
500-999 500-999 1000
1000-1499 (延遲)
1500-1999 (該包丟失)
2000-2499 2000-2499 1000, SACK=2000-2500
1000-2000 1000-1499 1500, SACK=2000-2500
1000-2000 2500, SACK=1000-1500
---------此為D-SACK
3000-3499 3000-3499 3500 (ACK包丟失)
3500-3999 3500-3999 4000 (ACK包丟失)
4000-4499 (該包丟失)
4500-4999 4500-4999 4000, SACK=4500-5000 (ACK包丟失)
3000-3499 3000-3499 4000, SACK=3000-3500, 4500-5000
---------此為D-SACK
5.3 數據段丟失和延遲
500-999 500-999 1000
1000-1499 (延遲)
1500-1999 (該包丟失)
2000-2499 2000-2499 1000, SACK=2000-2500
1000-2000 1000-1499 1500, SACK=2000-2500
1000-2000 2500, SACK=1000-1500
---------此為D-SACK
5.4 數據段丟失且延遲
500-999 500-999 1000
1000-1499 (延遲)
1500-1999 (該包丟失)
2000-2499 (延遲)
2500-2999 (該包丟失)
3000-3499 3000-3499 1000, SACK=3000-3500
1000-2499 1000-1499 1500, SACK=3000-3500
2000-2499 1500, SACK=2000-2500, 3000-3500
1000-2499 2500, SACK=1000-1500, 3000-3500
---------此為部分D-SACK
6. 結論
通過SACK選項可以使TCP發送方只發送丟失的數據而不用發送后續全部數據,提高了數據的傳輸效率。