學習了解 TCP(三次握手/四次揮手)

按照國際慣例,了解或者學習一個東西之前,先過一遍這個東西的定義。

TCP:

傳輸控制協議(英語:Transmission Control Protocol,縮寫為TCP)是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協議,由IETF的RFC 793定義。( 維基百科 )

TCP

TCP 相關知識點是我們程序員來說必須掌握的一個基本技能點?;旧鲜敲嬖嚤貑栴}( 當然大佬就不需要問了咯 )。

TCP 是在傳輸層上工作的一個比較復雜協議。比起 UDP 來說,TCP 的復雜程度簡直不是一個量級的關系。 了解傳輸層 —— 走你

TCP 特性

1.面向連接可靠的傳輸協議。
2.不支持組播地址,僅支持單播地址。
3.傳輸基于字節(jié)流,不是報文。
4.通過滑動窗口機制實現流量控制,根據網絡狀態(tài)動態(tài)改變窗口的大小進行擁塞控制。
5.支持對數據進行分節(jié)排序,保證數據完整型以及正確性。
6.通過序號的確認和重發(fā),確保傳輸的可靠性。

TCP 包頭

TCP 包頭

源端口號: 這個字段占了 UDP 包頭的前面的 16 bits( 兩個字節(jié) ). 一般是包含發(fā)送數據包的應用程序使用的端口。偶爾我們想實現單向傳輸的時候,就可以在源端口填 0,這樣接收端就不知道,發(fā)送端的端口地址。

目的端口: 16 bits表示接收端的應用程序的端口地址。

序列號:主要是在三次握手的時候,會同步這個數據,以保證數據的連續(xù)的正確,不會出現分節(jié)數據的亂序問題
當 SYN 標記不為 1 時,這是當前數據分段第一個字節(jié)的序列號,如果 SYN 的值是 1 ,這個字段的值就是初始序列值( ISN ), 用于對序列號進行同步,這時第一個字節(jié)的序列號比這個字段的值大 1 (也就是 ISN 加 1)。

確認號:主要用于數據確認的標識,保證數據的可靠性。如果丟包,通過確認號重發(fā)丟失的分節(jié)數據。這個數據只有在 ACK 為 1 時才有意義。
用于確認已經接收到的數據分節(jié),具體的數值是即將接收的下一個序列號,也就是已接收到的分節(jié)序列號加 1 。

數據偏移:表示的是包頭的長度,接收到可以知道那個地方數據就是真正的數據區(qū)。單位是 32 bits( 4個字節(jié) )。因為這個長度是 4 bits。所以最大是 15 。因此 TCP 的包頭最大是 60 個字節(jié)(包含端口號)。目前大多數是 20 字節(jié)。

保留:暫時未有使用,必須為 0,

URG:這個值為 1 時,標識緊急指針區(qū)域有效,督促中間層設備要盡快處理這些數據。

ACK:這個值為 1 時,標識確認號有意義。

PSH:當這個值為 1 時,表示 Push 操作,Push 操作就是數據到達接收到后,立即傳送給應用程序,而不需要在緩沖區(qū)排隊(正常情況下,需要等到緩存區(qū)塞滿之后上報給應用程序)。

RST:當這個值為 1 時,連接會被重置,用來針對那些錯誤或者非法連接。

SYN:當這個值為 1 時,表示同步序列號,主要是在建立連接的時候,三次握手時同步序列號。
在三次握手的時候 SYN = 1 ACK = 0 表示請求連接, SYN = 1, ACK = 1 表示連接被響應。

FIN:當這個值為 1 時,表示發(fā)送端的數據發(fā)送完成,沒有其他的數據了。這是一個連接斷開的標識。

窗口大?。?/strong>這是窗口滑動機制進行流量控制和窗口大小進行擁塞控制。這是一個很深的問題,后續(xù)的相關文章可以聊一聊。

檢驗和:這個檢驗和 UDP 一致,發(fā)端生成后,接收端通過二進制計算對接收的數據進行相關的校驗。確保數據的完整以及正確性

緊急指針:標識數據中有多少是緊急數據,緊急數據放在數據的開頭。

選項:額外的填充數據,確保包頭數據是 32 bits 的倍數關系。

數據:需要傳輸的數據。

理解數據協議是理解三次握手以及四次揮手、窗口的前提條件。

TCP 三次握手

TCP 是面向連接的,數據通信之前必須要建立連接,這個連接可以是 1 對多。

TCP 三次握手的過程
三次握手

上圖展示三次握手的流程圖,文字描述過程如下:
客戶端和服務端從 CLOSED 的狀態(tài)變成在線狀態(tài)。服務端需要處于 LISTEN.
1、客戶端向服務端發(fā)起一個連接。報文中包含了:
SYN = 1,
「序列號」的值,
發(fā)送之后客服端進入到 SYN-SENT 狀態(tài)。

2、服務端接收到 SYN 和 序列號信息后,需要對這個報文進行的確認。服務端收到客戶端發(fā)送過來的「序列號」的值,服務端會返回一個「確認號」的值(序列號+1)。同時返回
SYN = 1 表示還在同步階段。
ACK = 1 表示確認號有意義。
序列號:表示服務端的序列號 y。
確認號:針對客戶端發(fā)起連接的一個確認號。
服務端發(fā)送之后,進入到 SYN-RCVD 狀態(tài)。

3、客戶端接收到服務端返回的數據,使得客戶端這一邊的相關通信建立,并且同步了相關序列號和確認號的數值,但是服務端還沒有接收到客戶端回復的確認號。所以客戶端需要再發(fā)送一個數據到服務端,主要包含:
ACK = 1,這是確認號的數據有意義。
SYN = 0 序列號已經同步完成,不需要再同步序列號。
序列號:因為 SYN 已經不是第一次同步序列號的信息了。這個時候的序列號,就表示的是一個單純的基于序列號最新的數據包的序列號。其值為:x+1。
確認號:返回服務端序列號 y 的確認號,為 y+1。
發(fā)送這個值之后,客戶端進入到 ESTABLISHED 狀態(tài),服務端接受到這個值之后也進入到ESTABLISHED 狀態(tài)。然后就可以開始傳遞數據通信了。

至此三次握手已經完成。

TCP 為什么進行是三次握手?

為什么 TCP 需要進行三次握手,這個問題很多人的解釋都引用了

為了防止已失效的連接請求報文段突然又傳送到了服務端,因而產生錯誤。—— 謝希仁的《計算機網絡》

首先我們需要明白三次握手的意義在于什么,也就是說三次握手需要達到的一個目的是什么,
簡單來說,其實是為了同步序列號和確認號的相關信息,而序列號和確認號又是保障數據的正確性以及窗口滑動機制的最基本的根據。所以我最需要明白的可能還是為什么要同步序列號就是為什么要三次握手:(舉個例子來說明)(
如果 A 給 B發(fā)送一個數據包,這個包由于網絡的原因,很久才到 B 端,而這段時間,A 和 B 已經斷開,并且重新建立了連接關系。沒有相關同步序列號和確認號,B 端認為這個數據還是認為 A 這個時候要發(fā)給我的,但是其實這個數據上一次傳輸的數據,相當于這次傳輸的數據中插入了其他的數據,那么就會導致這次的數據出現異常。

對于每次連接的序列號基本都是不一樣的,這個序列號是隨著時間會變化的,這個是一個 4 個字節(jié)的計數器。每隔 4 ms就會自加 1。如果需要產生重復的,需要 4 個小時才會回到同一個序列號。4 個小時的時候,那么在網絡中的上一次數據包早已經失效了。在 IP 協議中,每個 IP 包頭都是有 TIL ( 生存時間的)。

為什么不是兩次:
對于 A 來看說,兩次實現了信息一來一回,但是 TCP 的數據的可靠性,如果要實現對于 B 來說的信息的一來一回,那么第三次是一定要存在的。對兩端的數據一來一回才是建立可靠連接的基本要求。

為什么不是四次:
理論上其實這個同步序列號和確認號的過程,大于三次也是沒有的,應該說幾十次上百次都是可以的,但是三次握手的過程已經實現了序號數據同步,在進行太多次的序號同步,已經沒有意義。無故浪費寬帶。

解析 TCP 四次揮手

當通信完成,當然需要能夠進行連接斷開。
TCP 四層揮手的過程:


TCP 四次揮手

1、任意一段( A 端)發(fā)出一條 FIN 的數據。數據包含:
FIN = 1,
序列號
A 端發(fā)出這個數據之后,進入到 FIN - WAIT -1 的狀態(tài),等待 B 端的回復.

2、B 收到 A 端的 FIN 的信息就回復一個數據,表示已經知道 A 端請求斷開連接這個事情了。此時 B 端進入到 CLOSED - WAIT 的狀態(tài)。A 端接收到這個數據進入到 FIN - WAIT -2 的狀態(tài)。 數據中包含 :
ACK = 1
確認號

3、B 端給 A 端發(fā)起一次 FIN 的數據。請求結束連接,發(fā)送完成之后 B 端進入到 LAST - ACK 狀態(tài)。發(fā)送的數據包含:
FIN = 1;
ACK = 1;
序列號
確認號

4、 A 端接收到這個 B 端發(fā)送的 FIN 數據進入到 TIME- WAIT 狀態(tài),同時回復 B 端,已經接收到了 FIN 數據。回復的包中包含:
ACK = 1;
確認號

至此整個過程全部結束。順利斷開連接。

其實上述是正常且十分順利的四次揮手。

其中會出現多次不同的異常。

異常1:如果在 FIN-WAIT - 1 A 端不能接收到 B 斷的 ACK 信息。TCP 協議層上是沒有對這個地方任何處理的,但是 LINUX 是有相關處理的,有一個 TIMEOUT 的參數。FIN-WAIT-1 這個過程中其實不容易出異常的。因為在 TCP 的協議中,每次發(fā)送一個數據,另外一端會立馬回復 ACK 確認信息的。所以理論上來說 A 端一般很少會能夠直接看到 FIN - WAIT 1.

A端:
FIN-WAIT 1 —— A 端可以數據都已經發(fā)送完成,但是 B 端可能還有數據處理完成。

FIN-WAIT 2 -- B 端回復了 A 端結束連接的請求,并且做出了返回之后, A 進入一種半關閉的等待的狀態(tài)。

TIME -WAIT —— 協議規(guī)定 A 端必須有一個駐守時間。這是一個為了異常處理而規(guī)定的時間。

B端:
COLSED - WAIT -- 數據沒有處理,處理完成沒有處理完的數據。

LAST - ACK -- 這是 B 給 A 端發(fā)送一個 FIN 請求之后,進入到一個等待 A 端回復的狀態(tài)。

異常2:在 B 端發(fā)送一個 FIN 之后, 由于種種原因 B 端沒有接收到 A 端的 ACK. 此時 根據 TCP 協議自身的機制 B 端重新發(fā)送 FIN 請求數據。但是如果這個時候 A 端已經回復了 B 的 ACK ,到了設置的 TIME - WAIT 的時間之后,就會關閉這個連接。如果后續(xù)還收到這個信息。那么直接會 RST ( 錯誤連接或者非法連接 )

為什么需要設置一個 TIME-WAIT 的時間:

這個文章講的特別好(https://blog.csdn.net/smileiam/article/details/78226816)

一、保證TCP協議的全雙工連接能夠可靠關閉
先說第一點,如果Client直接CLOSED了,那么由于IP協議的不可靠性或者是其它網絡原因,導致Server沒有收到Client最后回復的ACK。那么Server就會在超時之后繼續(xù)發(fā)送FIN,此時由于Client已經CLOSED了,就找不到與重發(fā)的FIN對應的連接,最后Server就會收到RST而不是ACK,Server就會以為是連接錯誤把問題報告給高層。這樣的情況雖然不會造成數據丟失,但是卻導致TCP協議不符合可靠連接的要求。所以,Client不是直接進入CLOSED,而是要保持TIME_WAIT,當再次收到FIN的時候,能夠保證對方收到ACK,最后正確的關閉連接。

二、保證這次連接的重復數據段從網絡中消失
再說第二點,如果Client直接CLOSED,然后又再向Server發(fā)起一個新連接,我們不能保證這個新連接與剛關閉的連接的端口號是不同的。也就是說有可能新連接和老連接的端口號是相同的。一般來說不會發(fā)生什么問題,但是還是有特殊情況出現:假設新連接和已經關閉的老連接端口號是一樣的,如果前一次連接的某些數據仍然滯留在網絡中,這些延遲數據在建立新連接之后才到達Server,由于新連接和老連接的端口號是一樣的,又因為TCP協議判斷不同連接的依據是socket pair,于是,TCP協議就認為那個延遲的數據是屬于新連接的,這樣就和真正的新連接的數據包發(fā)生混淆了。所以TCP連接還要在TIME_WAIT狀態(tài)等待2倍MSL,這樣可以保證本次連接的所有數據都從網絡中消失。

TCP 為什么進行是四次揮手?

斷開比連接更復雜,比較直接的理解是資源回收比資源分配會更麻煩。使得所有資源能夠有效并且不產生錯誤的情況下釋放。如上所述,四次揮手的意義。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容