TCP 學習筆記 --- Kindda Hu
08.12.15 [email protected]
Reference: TCP/IP詳解卷一/ RFC793 /
以下是個人總結, 語言方面若有看不習慣請見諒. 還有幾點不明白之處請指教,請參考#Issues to be comfired. 若本人總結有錯誤之處,請各位及時指出並告知.
########## TCP Header ###################
TCP Header Format 20Bytes
########## TCP 基本傳輸流程#################
Sender A ----------------> Receiver B
Step 1:Start 3-hands shake
SYN seq j ,mss ,win
a, ------------------------->
SYN seq q,mss,win; ACK ack j+1
b, <-------------------------
seq j+1 ACK ack q+1
c, ------------------------->
Step 2: Data flow
2.1 數據不需要分組,
seq j+1, ack NO (Length),
d, ------------------------->
ack (j+length+1), win size
e, <-------------------------
2.1 數據包進行分組轉發,絕大多數都需要如此發送:
seq j+1, ack seq no (Length),
f, ------------------------->
ack (j+length+2), win size
g, <-------------------------
seq j+length,ack no(length),win size,
h, ------------------------->
seq (j+length+length),ack no(length),win size,
i, ------------------------->
ack j+length+1;win size
j, <-------------------------
ack j+length+length+1;
k, ------------------------->
.................
Step 3, Close. FIN 4 hands shake
Fin seq j',
l ------------------------->
ACK seq j'+1
m <-------------------------
Fin seq q'
n <-------------------------
ACK seq q'+1
o ------------------------->
Step1 , TCP 建立, 3次握手; 下面爲正常的TCP session建立過程;
a. A主動建立TCP連接, 發送SYN 包, seq no爲當前定時器給的值j(參見關於SEQ NO),宣稱自己的MSS, window size;
b. B回覆ACK, ack no = j+1,並同時發SYN包給發A, seq no爲B自身定時器的值q, 並宣稱自己的mss和win size;
c. A收到B發來的SYN包後回覆ACK, ack no=q+1;
ps: Step1爲標準的正常TCP session建立流程,還有一些非正常現象,如A和B同時向對方發送SYN包,則通過4次握手只建立一個TCP session;
Step2, 數據傳輸, TCP session建立後,A給B發送數據包
2.1 數據不需要分組傳輸,每個數據包單獨傳輸.
d. A給B發送數據包,Seq no爲j+1,和步驟c中的seq no相同, 因爲A並沒有收到B發送新的ack no,length爲數據的長度(因爲需要發 送的數
據字節長度小於MSS和win size,所以不需要分段), (參考關於數據包分組(分段)傳輸標準);
e. B收到數據後給A回覆ACK, ack no爲j+1+length;
ps:
2.2 數據需要進行分組傳輸
f. A給B發送一個數據報文,seq no爲j+1, 長度爲length;
g.B給A剛纔的data報文回覆ACK, ack no爲j+1+length+1;
h.A收到B對於剛發送data包的ack後, 使用其ack no作爲seq no發送數據,length爲l';
i. A使用seq no爲 j+1+length+1+L'再次發送數據報文; (連續發送兩個數據包. 發送方接收到一個ack則增加一個發送數據包.因爲使用了慢啓動. 詳情
請參照 關於慢啓動)
j. B收到2個data包後回覆ack包(根據網絡情況和b決定. 只回復一個ack或者針對每個data都回復ack. 具體參考關於接收方什麼時候回覆ACK報文)
k. 很步驟h類似, 這次發送的data數根據收到的ack報文來決定,收到n個則再增加n個;
Step3, 結束TCP Session,
TCP session的結束類似於TCP session的建立(只不過將給對方的ack和自己的fin請求區分開了), 需要分別想對方發送FIN請求,並得到對方的ack後
才close掉此鏈接;
l. 當數據發送完成後,發送方A給接收方B發送FIN結束請求, seq爲j';
m.B收到Fin後,回覆ACK報文給A;
n.B給A發送FIN請求結束報文;
o.A收到ACK後結束對B的TCP 狀態調整爲closed; 並在收到B發送的Fin後,回覆ACK給B; B在收到ack後將自己對於A的tcp狀態調整爲closed;
ps: 有的TCP版本中,結束時只進行單方面結束,即兩次握手,A給B發FIN,B回覆ACK,但是不發送Fin請求;
######### TCP 狀態變遷 ###############
# 如下圖爲TCP狀態機圖
#如下圖爲正常的T C P連接的建立與終止過程中,客戶與服務器所經歷的不同狀態。
Ps: 主動結束的需要先進入Time-wait狀態後經過2MSL後進入Closed狀態;
被動結束的,只需要在LAST-ACK狀態中收到ACK回覆即可進入Clolse狀態;
因爲提出主動結束的大都爲客戶端,所以服務器被動結束,直接進入Closed狀態.
### 下面爲TCP 各種狀態的具體說明
A connection progresses through a series of states during its
lifetime. The states are: LISTEN, SYN-SENT, SYN-RECEIVED,
ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK,
TIME-WAIT, and the fictional state CLOSED.
CLOSED is fictional because it represents the state when there is no TCB, and therefore,no connection. Briefly the meanings of the states are:
LISTEN - represents waiting for a connection request from any remote
TCP and port. 監聽狀態;
SYN-SENT - represents waiting for a matching connection request
after having sent a connection request. Syn已經發出狀態;
SYN-RECEIVED - represents waiting for a confirming connection
request acknowledgment after having both received and sent a
connection request. 收到SYN,回覆ack併發送SYN包;
ESTABLISHED - represents an open connection, data received can be
delivered to the user. The normal state for the data transfer phase
of the connection. 收到針對自己發出SYN包的ACK報文,則變成Estab狀態;
FIN-WAIT-1 - represents waiting for a connection termination request
from the remote TCP, or an acknowledgment of the connection
termination request previously sent. 主動結束中,發送FIN報文,並等待ACK或者Fin的階段;
FIN-WAIT-2 - represents waiting for a connection termination request
from the remote TCP. 主動結束中,接收到針對自己發出FIN包的ACK.並等待對方FIN包的階段;
CLOSING - represents waiting for a connection termination request
acknowledgment from the remote TCP. 主動結束中,在FIN-Wait1狀態,等待對方ACK包的過程中收到對方的主動結束請求FIN包,則進入CLOSING階段;
TIME-WAIT - represents waiting for enough time to pass to be sure
the remote TCP received the acknowledgment of its connection
termination request.
CLOSE-WAIT - represents waiting for a connection termination request
from the local user.被動結束中,收到對方的FIN請求,回覆ACK報文的階段;
LAST-ACK - represents waiting for an acknowledgment of the
connection termination request previously sent to the remote TCP
(which includes an acknowledgment of its connection termination
request). 被動結束中,在COLSE-WAIT的基礎上,發送FIN請求後,等待ACK報文的階段 ;
CLOSED - represents no connection state at all. 主動結束時,由Time-WAIT經過2msl到達Colsed; 被動結束時, 由LAST-ACK報文收到最後的ack後進入的狀態.
################## 相關概念 ###########################3
sender 相關概念:MTU,MSS,window size 的左邊, Cwnd(congetion window size)和 慢啓動門限ssthresh, RTT, RTO,
Receiver 相關概念: MRU,MSS,window size的右邊, window size,buffer size, tcp 處理進程, 回覆ack. window size , buffer size , seq no, ack no
#關於PUSH標記
若接收方收到一個帶PSH標誌的包,則立即提交到TCP進程進行處理,並回復ACK. 若數據包中不帶PSH標記, 則是由分組到齊或者buffer size到一定程度上將數據
提交到TCP處理進程中.
#關於SEQ NO
seq NO 爲數據包發送的序列號, TCP 報頭中包括Seq no 和 ack seq NO,分別佔4個字節, 所以其值爲[ 0- 65535x65535].
第一個syn包中的seq no值由發送方的定時器決定. Seq No 由一個定時器維護着,每隔4ms, seq+1, 達到最大值後繼續衝最小值開始循環, 如此反覆;
數據傳輸時的seq no (我認爲)爲ack回覆的ack no爲準, = sender's seq +1;也可是發送方的原seq no+Length+1; (RFC793中如此規定,但是也有不同實現的.)
#關於DATA Offset
數據開始的偏移位數,就是說從x個字節開始爲數據, x之間的爲TCP Header,所以也可解釋爲TCP 頭部的長度. 但是x=nx4;如offset這4個bit爲1000的話,則10進製爲8,所以tcp header長度爲8x4=32;
###### 關於定時器 ##########
## 關於堅持定時器 Persist Timer:
即窗口大小檢測定時器, 發送方通過該定時器定期查詢接收方窗口狀態. 防止一下情況產生,
a, receever win size爲0,並通知sender,sender 暫停發送報文,並等待窗口更新報文ack的到來;
b, receiver 窗口更新, 發送ack通知sender,但是該ack包被丟失.
c, 則出現了, sender 等待win size更新報文,不發送數據; receiver 等待sender發送新的數據的 雙方互等的情況發生.
persist timer 在收到win size爲0的ack包時被啓動,然後每隔一段(5s)時間進行查詢.
receiver 的window size 需要從從0更新到大於1/2的buffer size的時候,才告知sender,否則仍然宣稱win = 0 ;
## 關於保活定時器 Keepalive Timer:
可以理解爲TCP Session timeout keepalive time, 當建立好的tcp session處於空閒時,雙方都處於Established狀態,保活定時器則可以在一段時間以後自動停
止該tcp session. 但是RFC和有的TCP版本並不支持該定時器.
## 關於2MSL 定時器
##關於判斷是否分組的標準:
首先理解下面幾個概念: 需要傳輸的數據字節數, MSS,MTU, Window size;
#關於需要傳輸的數據字節數.
既被傳輸數據的字節個數. (如"Hello World"爲10個字節.若每次只發送一個hello world,則每次爲10個字節; 若一次發送200個hello word,則需要傳輸的字節數
爲2000個字節;)
#關於MSS/MTU/WINDOW SIZE則參考關於MSS,關於MTU和關於Window size;
#關於MTU
MTU 爲最大傳輸單元,基於不同的鏈路層的. Ehternet MTU 爲1518, SLIP爲259, 所以相對爲IP層來說,MTU= 1518-18(DMAC 6+SMAC 6+
TYPE/LENGTH 2+ CRC 4)= 1500; 相對於PPPoE來說,MTU= 1492=1500-8(PPP);
#關於MSS
MSS 是TCP協議裏面的一個概念,爲發送端最大發送的TCP報文中數據字段的大小,必須小於MTU,通常爲 1460=
MTU-IPHead-TCPhead=1500-20-20=1460;
若A-B都在同一網段,則MSS爲1460,若不在同一網段,而且程序沒有指定的話,使用默認536;
MSS一般在TCP session建立階段 三次握手時宣稱和協商.
#window size
window size 接收端用來申明自己可以接收到的數據大小爲窗口; 接收端用此來處理數據擁塞;
數據傳輸時, 窗口是滑動的, 可以理解爲窗口大小爲從A到B,則A代表窗口的左邊, B代表窗口的右邊, 所以Window size == B-A; 在傳輸過程中B和A都向後滑動,
當B=A時, 則window size == 0, 接收方此時不能接收任何數據, 並通知發送方讓其停止發送數據, 當窗口大小更新後,發送ack通知sender告知window 大小,讓
sender繼續發送數據.
發送端左邊A向右移動,是因爲受到接收端的ack包,並將左邊A移動到ack no的地方.
接收端window size右邊B向右移地取決於, 接收端進程處理tcp數據並釋放緩存的能力。 當緩存沒有釋放完全時,接收端則通過ack給發送端通告當前window
size的大小,待恢復或者變大時,發ack包通知, ack no和之前的ack包中的no 相同。 所以說buffer可以大於緩存。
接收方回覆ACK的時機 取決於接收方window size的大小(接收方在發送一個A C K前不必等待窗口被填滿)和接收到的包中是否帶有PUSH標記.)?
下面說一下我對於什麼時候需要對數據包分段的理解:
比如說一個正常的數據傳輸, MSS=1460,MTU=1500,Win size=65535; 當前win size爲B通告的爲win size'時,
1, 當要發送數據字節個數<MSS;且又<win size' 時; 不需要分組發送; 如發送hello word 或者通過telnet登錄時傳輸user/password的報文;
2, 當要發送數據字節數>MSS;且又>win size'時, 則需要進行分組發送;如ftp傳輸大文件,或者一次傳輸200個hello world(注意:一次發送200個hello world和發
送200次hello word是不一樣的. 前者需要分組,2個date報文搞定(length分別是1460+540)和一個ack報文;而後者則需要200個date報文(每個length=10),和
x(有時爲200個,有時爲x個,請參考關於接收方什麼時候回覆ACK報文)個ack報文.);
##關於如何決定是否重發數據包.(如何界定包已經丟失並重傳?)
1,RTO超時;
2,連續收到3個相同Seq no的ack包,發送方則認爲丟包.
#### TCP 對分組包丟失的處理 #########
當分組傳輸的數據被丟失後, 接收端通過對收到的數據進行處理髮現後,必須發送ack報文通知發送方重新發送.
因爲TCP無法告知對方缺少那一段,所以採用發送方將自己最後一個成功回覆的ack包發送給對方的方式,來告訴對方應該從該seq no處將數據包進行重發.
發送方連續收到3個相同的ACK時, 則認爲有包被丟棄,並重傳自那個序號起的一段報文.
當接收方處於通知對方丟包並且在等待丟失包到來的狀態時, 對收到的數據包只進行保存,不會上傳到進程進行處理.
當接收方收到丟失包且發現沒有其他丟包時, 將緩存的數據全部提交給進程進行處理.
# 慢啓動和擁塞避免
Congetion window 發送端每次發送數據包的個數大小,當cwnd<= ssthresh時,每當收到一個ack,cwnd+1; 當cwnd>ssthersh時,則每次增
加1/cwnd,則cwnd=cwnd+1/cwnd. 發送方用此來進行數據擁塞的處理.
## 關於重傳超時定時器 Retransmission TimeOut / RTT :
RTO 爲超時重傳時間. 當RTO時間內未收到對方的ack,則認爲超時,重發數據包;
而RTO值是有RTT計算出來, RTT 爲往返時間, 爲發送方發出一個seq no的報文,到收到該報文ack 回覆的時間段.由於網絡流量變化,所以TCP需要跟蹤這些變化,
並算出相應的值; 所以TCP中判斷是否超時,重傳最主要的就是要進行RTT的計算.
sender 每次發送數據要先檢測RTT 測量定時器是否被啓動,若沒有的話則啓動該定時器, 若已經啓動的話則不更新.
因爲TCP中ack和seq no的回覆並不可能是一一對應,所以需要算法來計算RTT的值;
### Issues to be confirmed #####
1, 接收方什麼時候會將buffer中的數據提交到TCP進程當中去?
包中帶psh標記, buffer 到什麼程度? 還是等分組全部收到? 或者自己有什麼定時器?
2, TCP 不對ack報文進行確認,只對帶有帶有數據的ack報文進行確認. 應該如何理解!!????????
3, RTO 本身有定時器? rtt測量定時器!? 是否是每次發送方發送數據前要確認啓動的定時器?
4,關於接收方B什麼時候回覆ACK報文?
5,關於2MSL 定時器