协议簇:TCP 解析: Sequence Number
簡介
序列號(Sequence Number) 是 TCP 協議中非常重要的一個概念,以至于不得不專門來學習一下。這篇文章我們就來解開他的面紗.
在 TCP 的設計中,通過TCP協議發送的每個字節都對應于一個序列號. 由于每個字節都有自己的序列號,那么每個字節都可以被對方確認接收.
但是由于 TCP 使用累計確認機制,因此不需要對每個接收到的字節都發送對應的ACK,而是采用確認最后接收到的自己的序列號的方式來進行確認接收的. 舉個例子,對于序列號 X, 它意味著 X 之前的所有字節已經被對方接收到(不包含 X 本身)。
序列號這個機制使得 TCP 可以檢測到重復的數據包.
本篇文章中將會使用都很多我們在基本部分引入的專業術語,請參考 協議簇:TCP 解析: 基礎
系列文章
協議簇:TCP 解析:基礎
協議簇:TCP 解析:建立連接
協議簇:TCP 解析:連接斷開
協議簇:TCP 解析:Sequence Number
協議簇:TCP 解析:數據傳輸
Sequence Number
正如我們所知道的,Sequence Number 字段在 TCP 頭部占用 32bit 的長度。這也意味著 Sequence Number 是有限的,它的合法值是 0 - 2**32 -1. 因此對于通信雙方,在發送 SEQ 時,總是需要將該值與 2 ** 32 取模.
TCP 任何一方在接收到對方發送的數據包之后,都需要對 Sequence Number 進行檢查。 最通常的檢查包含以下幾條:
概念引入
SND.UNA - 最早發送且沒有收到ACK的 Sequence Number
? ????????????????? [oldest unacknowledged sequence number]
SND.NXT - 下一個被發送的數據的 Seuqnce Number
????????????????????[next sequence number to be sent]
SEG.ACK - 接收到的 TCP 段的 ACK,其中包含了對方期待下一個段的 Sequence Number
????????????????????[acknowledgment from the receiving TCP (next sequence
number expected by the receiving TCP)]
SEG.SEQ - 一個 TCP 段的第一個字節的 Sequence Number
????????????????????[first sequence number of a segment]
SEG.LEN - 一個 TCP 段中包含的字節的數量
????????????????????[the number of octets occupied by the data in the segment
(counting SYN and FIN)]
SEG.SEQ+SEG.LEN-1 - 一個 TCP 段的最后一個字節的 Sequence Number
????????????????????[last sequence number of a segment]
RCV.NXT - 下一個期待接收到的段的第一個字節的 Sequence Number. 同時,這個值也代表了接收方的接收窗口的下限.
???????????????????[next sequence number expected on an incoming segments, and is the left or lower edge of the receive window]
RCV.NXT+RCV.WND-1 - 下一個期待接收到的段的最后一個字節的 Sequence Number. 同時,這個值也代表了接收方的接收窗口的上限
??????????????????[last sequence number expected on an incoming segment, and is the right or upper edge of the receive window]
對于數據發送方
在發送了 TCP 數據之后,正常情況下,我們都會收到相應的 ACK.
接收到的 ACK 需要滿足條件: SND.UNA < SEG.ACK =< SND.NEXT
當一個處于重傳隊列的段的SEQ + 它的長度的和小于 ACK 的值,那么這個段已經被對方成功接收,可以從重傳隊列中移除。
對于數據接收方
接收到的段中包含的 SEQ 需要滿足以下條件:
RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND (確保接收到的數據的第一個字節的 SEQ 處于接收窗口中)
OR
RCV.NXT =< SEG.SEQ+SEG.LEN-1 < RCV.NXT+RCV.WND (確保接收到的數據的最后一個字節的 SEQ 處于接收窗口中)
滿足上述條件中任何一個條件,便可以判斷當前接受到的數據部分處于接收窗口.
實際情況中,我們還需要考慮接收窗口為 0 和 空 TCP 段的情況. 那么就需要考慮以下四種情況:
| 0 | 0 | SEG.SEQ = RCV.NXT |
| 0 | >0 | RCV.NXT =< SEG.SEQ < RCV.NXT+RCV.WND |
| >0 | 0 | not acceptable |
| >0 | >0 | RCV.NXT =< SEG.SEQ < RCV.NXT + RCV.WND OR RCV.NXT =< SEG.SEQ+SEG.LEN-1<RCV.NXT+RCV.WND |
注意,當接收窗口為 0 之后,除了ACK之外,無法接收任何其他 TCP 段. (對于上表第三條)
Initial Sequence Number Selection
TCP 協議并不限制在 TCP 的實現中重復使用同一個連接. 一個連接僅僅由一對 socket 標識. (新的連接被成為前一個連接的“化身”[incarnation]) 但是存在一個問題: 如何判斷一個TCP段來自前一個連接還是前一個連接的化身? 當一個連接被快速的打開關閉或者一個連接由于內存不足而斷掉,恢復后又重新建立的情況下,會尤其明顯.
在上述問題中,很有可能兩個連接使用相同的序列號發送數據。這種情況下,我們無法區分這個數據包的來源. 因此,對于 TCP 而言,選擇一個合適的 Sequence Number 非常重要.
當我們嘗試建立一個連接時,我們需要在SYN中附上我們選擇的 Sequence Number,也就是 Initial Sequence Number,簡稱 ISN. ISN 的生成方法如下:
ISN 生成器以當前機器時鐘為基礎,粗略地每4微妙增加ISN的最低有效位.
這個生成器生成的序列會以 4.55 小時為周期重復,但是設計者認為沒有TCP段可以在網絡上存活超過這個時間,因此他們認為這樣選擇 ISN 是非常合理的.
對于每個TCP連接,都包含兩個 Sequence Number,分別由 TCP 雙方獨立生成. 在一個 TCP 連接建立之前,雙方應該回想通告自己的 Sequence Number (協議中稱之為“synchronize”). 互相通告自己的 Sequence Number 需要每方均發送自己的 ISN 并收到對方發送的 ACK, 以確保對方收到了己方的 ISN.
大體的流程如下:
又由于 TCP 連接是全雙工的,在接收的同時可以發送數據,那么2,3步可以合并為一步。最后, 就有了現在的 “三次握手" 了.
END!!!
總結
以上是生活随笔為你收集整理的协议簇:TCP 解析: Sequence Number的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: “Hello,Github!——如何配置
- 下一篇: 探索比特币源码4-JSON-RPC接口的