本文將簡單介紹tcp協議的基本內容,主要包括一下四部分:
• tcp概述
• TCP可靠資料傳輸
• TCP流量控制
• TCP連線管理
TCP概述
• tcp是一個點對點端到端的傳輸協議,有一個傳送方和接收方。
• tcp傳輸的是可靠的按序到達的位元組流
• tcp採用流水線機制,提高傳輸的效率。TCP通過擁塞控制和流量控制機制來控制滑動視窗的大小
• tcp協議分別設定了傳送方快取和接收方快取
• tcp採取全雙工(full-duplex)傳輸,也就是傳輸過程中,同一連線可以傳輸雙向的資料流,傳送方可以傳給接收方,接收方也可以傳給傳送方。
• tcp是面向連線的協議,通訊雙方在傳送資料之前必須建立連線。連線狀態只在連線的兩端中維護,在沿途節點中並不維護狀態。TCP連線包括:兩臺主機上的快取、連線狀態變數、socket等
• tcp實現了流量控制機制
TCP段結構
TCP: 序列號和ACK
序列號:
• 序列號指的是segment中第一個位元組的編號,而不是segment的編號
• 建立TCP連線時,雙方隨機選擇序列號
ACKs:
• 希望接收到的下一個位元組的序列號
• 累計確認:該序列號之前的所有位元組均已被正確接收到
Q: 接收方如何處理亂序到達的Segment?
• A: TCP規範中沒有規定,由TCP的實現者做出決策
上圖我們進行一個分析,以便搞清楚tcp序列號和ack的應用
首先,hostA作為傳送方給B傳送資料,隨機選擇一個序列號seq = 42,也就是這段segment中的第一個位元組的編號,並且設定ack=79,這表示,希望接收方回傳seg=79作為確認訊號代表接收方已經正確接受了這段資料
然後HostB成功接收到資料,想傳送方返回確認資訊,根據傳送方的ack,所以確認的seg=79,然後通過ack告知希望接收到的下一個位元組的序列號,並同時表示之前的所有位元組均已被正確接收,所以傳送ack=43告知已經接收到43號之前的位元組,並希望傳送方傳送43號位元組
TCP可靠資料傳輸
接下來我們看看tcp協議是如何實現可靠傳輸的。
• TCP在IP層提供的不可靠服務基礎上實現可靠資料傳輸服務
• 流水線機制
• 累積確認
• TCP使用單一重傳定時器
• 觸發重傳的事件:超時和收到重複ACK
RTT和超時
問題:如何設定定時器的超時時間?
• 大於RTT, 但是RTT是變化的
• 過短:不必要的重傳
• 過長: 對段丟失時間反應
問題:如何估計RTT?
SampleRTT: 測量從段發出去到收到ACK的時間忽略重傳
SampleRTT變化,測量多個SampleRTT,求平均值,形成RTT的估計值EstimatedRTT
EstimatedRTT = (1- ?)EstimatedRTT + ?SampleRTT
指數加權移動平均
典型值:0.125
TCP傳送方事件
從應用層收到資料後,會進行以下幾個步驟:
• 建立segment
• 序列號是segment第一個位元組的編號
• 開啟計時器
• 設定超時時間TimeOutInterval
如果發生超時事件:
• 重傳引起超時的segment
• 重啟計時器
收到ACK:
• 如果確認此前未確認的Segment,更新SendBase,如果視窗中還有未被確認的分組,重新啟動定時器
傳送端偽碼
`
TCP重傳示例
NextSeqNum = InitialSeqNum
SendBase = InitialSeqNum
loop (forever) {
switch(event)
event: data received from application above
create TCP segment with sequence number NextSeqNum
if (timer currently not running)
start timer
pass segment to IP
NextSeqNum = NextSeqNum + length(data)
event: timer timeout
retransmit not-yet-acknowledged segment with
smallest sequence number
start timer
event: ACK received, with ACK field value of y
if (y > SendBase) {
SendBase = y
if (there are currently not-yet-acknowledged segments)
start timer
}
} /* end of loop forever */
複製程式碼
快速重傳機制
TCP的實現中,如果發生超時,超時時間間隔將重新設定,即將超時時間間隔加倍,導致其很大,重發丟失的分組之前要等待很長時間.
通過重複ACK檢測分組丟失,Sender會背靠背地傳送多個分組,如果某個分組丟失,可能會引發多個重複的ACK.
如果sender收到對同一資料的3個ACK,則假定該資料之後的段已經丟失.
快速重傳:在定時器超時之前即進行重傳
演算法
C++程式碼
event: ACK received, with ACK field value of y
if (y > SendBase) {
SendBase = y
if (there are currently not-yet-acknowledged segments)
start timer
}
else {
increment count of dup ACKs received for y
if (count of dup ACKs received for y = 3) {
resend segment with sequence number y
}
複製程式碼
TCP流量控制
接收方為TCP連線分配buffer
上層應用可能處理buffer中資料的速度較慢
流量控制:傳送方不會傳輸的太多、太快以至於淹沒接收方(buffer溢位)
(假定TCP receiver丟棄亂序的segments)
Buffer中的可用空間(spare room) = RcvWindow
= RcvBuffer-[LastByteRcvd -LastByteRead]
複製程式碼
Receiver通過在Segment的頭部欄位將RcvWindow 告訴Sender。 Sender限制自己已經傳送的但還未收到ACK的資料不超過接收方的空閒RcvWindow尺寸。
Receiver告知SenderRcvWindow=0,會出現什麼情況?
會出現卡死,傳送方不發資料了。關於這些問題具體會在tcp擁塞控制裡面討論。
TCP連線管理
TCP sender和receiver在傳輸資料前需要建立連線。
三次握手機制
第一次握手: client host sends TCP SYN
segment to server
• specifies initial seq #
• no data
第二次握手: server host receives SYN, replies
with SYNACK segment
• server allocates buffers
• specifies server initial seq. #
第三次握手: client receives SYNACK, replies
with ACK segment, which may
contain data
四次握手機制
TCP連線管理:關閉
Step 1: client向server傳送TCP FIN 控制segment
Step 2: server 收到FIN, 回覆ACK. 關閉連線, 傳送
FIN.
Step 3: client 收到FIN, 回覆ACK.
• 進入“等待” –如果收到FIN,會重新傳送ACK
Step 4: server收到ACK. 連線關閉.
由於TCP連線是全雙工的,因此每個方向都必須單獨進行關閉。這原則是當一方完成它的資料傳送任務後就能傳送一個FIN來終止這個方向的連線。收到一個 FIN只意味著這一方向上沒有資料流動,一個TCP連線在收到一個FIN後仍能傳送資料。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
(1) TCP客戶端傳送一個FIN,用來關閉客戶到伺服器的資料傳送(報文段4)。
(2) 伺服器收到這個FIN,它發回一個ACK,確認序號為收到的序號加1(報文段5)。和SYN一樣,一個FIN將佔用一個序號。
(3) 伺服器關閉客戶端的連線,傳送一個FIN給客戶端(報文段6)。
(4) 客戶段發回ACK報文確認,並將確認序號設定為收到序號加1(報文段7)。
更多閱讀
為什麼成為一名程式設計師這麼困難? — 從程式新手到準工程師的必經之路
相信自己,沒有做不到的,只有想不到的
微信公眾號:終端研發部