TCP 协议(包含三次握手,四次挥手)
TCP 特性
- 1.確認應答機制 (ACK)
- 2.超時重傳
- 3.1建立連接 - 三次握手 ▲
- 3.2.斷開連接 - 四次揮手 ▲
1.確認應答機制 (ACK)
確認應答是可靠傳輸?shù)淖詈诵臋C制
接收方反饋一個應答報文(ACK),表示已收到
假設現(xiàn)在 A 想去 B 家里玩游戲,于是 A 給 B 發(fā)消息,若消息沒有出現(xiàn)錯誤且順序正確
結(jié)果如下所示:
但網(wǎng)絡傳輸比較復雜,可能存在一種情況"后發(fā)先至"
由于數(shù)據(jù)的長度不同或者傳輸網(wǎng)絡不同,先發(fā)送的數(shù)據(jù)不一定先到達,接收方接收到的數(shù)據(jù)可能是亂序的,如圖:
當 B 回復 A 的消息時,若存在對應關(guān)系,那么即使出現(xiàn)了"后發(fā)先至"的情況,也能順利的確立應答
上述方法,雖然可以順利的確立應答,但額外的信息很多,占用的帶寬很多
下面如圖,針對發(fā)送的請求進行編號,應答的時候也針對編號進行應答,這樣既能保證數(shù)據(jù)傳輸沒有歧義,也不會浪費太多的空間和帶寬
序號和確定序號,在前面 TCP報文格式中提到過
上述情況不嚴謹,真實的 TCP 還不一樣,TCP 是面向字節(jié)流的,此處的編號并不是按照一條兩條來編的,而是按照字節(jié)來編號的 (每個字節(jié)有一個編號)
確認應答是一種特殊的報文(ACK),所謂的應答報文,本質(zhì)上就是 ACK 字段為1 的報文,此時報頭中的"確認序號"字段才是生效的
初始序號是隨機的,為了防止網(wǎng)絡攻擊;如果發(fā)送多個數(shù)據(jù),每個數(shù)據(jù)都會帶著一個序號
接收方收到數(shù)據(jù)后,是知道數(shù)據(jù)所帶著的序號的,根據(jù)序號給出確認序號(告訴發(fā)送方下次給我發(fā)的序號),發(fā)送給發(fā)送方,發(fā)送方就知道接收方收到了哪些數(shù)據(jù)
2.超時重傳
確認應答是比較理想的情況,但數(shù)據(jù)在傳輸過程中,可能是會丟包的
仍以上面例子為例,A 給 B 發(fā)消息,你在家嘛?等了很久,A 也沒收到 B 的消息,此時,存在以下幾種情況:
① B 不想回 A 的消息
② B 沒收到 A 的消息 (丟包情況1: 發(fā)的請求丟失)
③ B 回復了消息,但 A 沒收到 (丟包情況2: 應答的 ACK 丟失)
②③情況:丟包的兩種情況,對于發(fā)送方來說無法確定是哪種情況,因此,進行統(tǒng)一處理:當發(fā)送了一條數(shù)據(jù)之后,TCP 內(nèi)部就會自動啟動一個定時器,達到一定時間也沒收到 ACK,定時器就會自動觸發(fā)重傳消息的動作 —— 超時重傳
①情況:
思考:
假設第二次重發(fā)沒有成功,那么就存在兩個超時時間 t1,t2 如圖所示:
那么,t1 和 t2 時間一樣長嗎??
在 TCP 中,t2 會比 t1 更長
TCP 抱著一種 “悲觀的態(tài)度”,當一次丟包重傳之后,TCP 就覺得大概率后面的重傳也沒用,所以就隔一個更長的時間,節(jié)省帶寬
上述丟包有兩種情況,一種是請求丟失 —— 重傳沒有問題;一種是 ACK 丟失,重傳就意味著接收方收到了相同的數(shù)據(jù)
TCP 會在內(nèi)部進行數(shù)據(jù)去重 (以序號為 key 進行去重),保證應用層讀到的數(shù)據(jù)不是重復數(shù)據(jù)
確認應答 和 超時重傳是 TCP 可靠性中最核心的機制
3.1建立連接 - 三次握手 ▲
為什么要就建立連接?
1.更好的保證可靠性: 建立連接的過程其實就是讓通信雙方驗證各自的發(fā)送能力和接受能力是否正常
2.協(xié)商一些重要參數(shù) (如: 序號的初始值)
具體怎樣建立連接?
舉例:A 給 B 打電話,打電話同樣要驗證自己以及對方的話筒和聽筒是否正常工作
第一次握手: 剛開始,A 不知道自己和 B 手機的聽筒和話筒是否正常,所以 A說"喂,你能聽到嗎?"
第二次握手: B 聽到后,說明 A 的話筒和 B 的聽筒正常,但 B 還需進一步檢查自己的話筒和 A 的聽筒是否正常;同時 B 把 A 話筒正常和自己聽筒正常的消息傳遞給 A;于是 B “我能聽到,你呢?”
第三次握手: A 收到 B 的消息后,就證明了 A 聽筒正常,B 話筒正常
以上三次握手就保證了 A、B 的聽筒和話筒都正常,也就保證了通話的正常,這就類似于網(wǎng)絡建立連接時的三次握手
TCP 中真實的建立連接過程: (假設主機 A 主動發(fā)起連接)
-
第一次握手: 客戶端向服務器發(fā)送 SYN 報文 (SEQ=x,SYN=1),并進入 SYN_SENT 狀態(tài),等待服務器確認
-
第二次握手: 實際上是分兩部分來完成的,即 SYN+ACK (請求和確認) 報文
服務器收到了客戶端的請求,向客戶端回復一個確認信息 (ack=x+1)
服務器再向客戶端發(fā)送一個 SYN 包 (SEQ=y)建立連接的請求,此時服務器進入 SYN_RECV 狀態(tài) -
第三次握手: 客戶端收到服務器的回復 (SYN+ACK 報文0);此時,客戶端也要向服務器發(fā)送確認包 (ACK);此包發(fā)送完畢客戶端和服務器進入 ESTABLISHED 狀態(tài),完成 3 次握手
建立連接的過程,相當于通信雙方各自給對方發(fā)送 SYN,在各自給對方發(fā)送給 ACK,只不過中間的 ACK 和 SYN 合二為一了,于是最后就是"三次握手"
幾個重要的狀態(tài):
- LISTEN: 正在偵聽來自遠方的 TCP 端口的連接請求,服務端啟動后處于 LISTEN 狀態(tài)用于監(jiān)聽不同客戶端的 TCP 請求并建立連接
- SYN_SEND / SYN_RCVD: 建立連接的中間過程,若連接順利的話(建立連接過程也可能丟包),這兩個狀態(tài)就一瞬消失
- ESTABLISHEN: 連接建立完畢 (驗證了通信雙方的發(fā)送和接受能力都正常),可以進行數(shù)據(jù)傳輸
1.兩次握手可以嗎??
不可以
- 防止已失效的請求報文又傳送到了服務端,建立了多余的鏈接,浪費資源
- 兩次握手只能保證單向連接是通暢的 (為了實現(xiàn)可靠數(shù)據(jù)傳輸, TCP 協(xié)議的通信雙方,都必須維護一個序列號,以標識發(fā)送出去的數(shù)據(jù)包中,哪些是已經(jīng)被對方收到的;三次握手的過程即是通信雙方相互告知序列號起始值,并確認對方已經(jīng)收到了序列號起始值的必經(jīng)步驟;如果只是兩次握手,至多只有連接發(fā)起方的起始序列號能被確認,另一方選擇的序列號則得不到確認)
.
2.為什么是三次??
主要是為了建立可靠的通信通道,保證客戶端與服務端同時具備發(fā)送、接收數(shù)據(jù)的能力
.
3.四次握手可以嗎??
可以,但沒必要
四次握手可以驗證雙方的發(fā)送接收能力正常,但是這樣做效率比較低
.
3.2.斷開連接 - 四次揮手 ▲
三次握手: 雙方各自向?qū)Ψ桨l(fā)起建立連接的請求,再各自給對方回應,只不過,中間的 SYN 和 ACK 能合并在一起
四次揮手: 雙方各自向?qū)Ψ桨l(fā)起建立連接的請求,再各自給對方回應,只不過,中間的 FIN 和 ACK 不一定能合并在一起
仍以打電話為例,如下圖:
TCP 中真實的斷開連接過程: (假設主機 A 主動斷開連接)
- 第一次揮手: 客戶端向服務器端發(fā)送斷開 TCP 連接請求的 [FIN,ACK] 報文,在報文中隨機生成一個序列號 SEQ=u,表示要斷開 TCP 連接
此時,客戶端進入FIN_WAIT_1 (終止等待1) 狀態(tài) - 第二次揮手: 當服務器端收到客戶端發(fā)來的斷開 TCP 連接的請求后,回復發(fā)送 ACK 報文,表示已經(jīng)收到斷開請求。回復時,隨機生成一個序列號 SEQ=v;由于回復的是客戶端發(fā)來的請求,所以在客戶端請求序列號 SEQ=u 的基礎上加 1,得到 ack=u+1
此時,服務端就進入了CLOSE_WAIT (關(guān)閉等待) 狀態(tài),客戶端收到ACK后,就進入FIN_WAIT_2 (終止等待2) 狀態(tài) - 第三次揮手: 服務器端在回復完客戶端的 TCP 斷開請求后,不會馬上進行 TCP 連接的斷開。服務器端會先確認斷開前,所有傳輸?shù)娇蛻舳说臄?shù)據(jù)是否已經(jīng)傳輸完畢。確認數(shù)據(jù)傳輸完畢后才進行斷開,向客戶端發(fā)送 [FIN,ACK] 報文,設置字段值為 1。再次隨機生成一個序列號 SEQ=w;由于還是對客戶端發(fā)來的 TCP 斷開請求序列號 SEQ=u 進行回復,因此 ack 依然為 u+1
此時,服務器就進入了LAST_ACK (最后確認) 狀態(tài) - 第四次揮手: 客戶端收到服務器發(fā)來的 TCP 斷開連接數(shù)據(jù)包后將進行回復,表示收到斷開 TCP 連接數(shù)據(jù)包。向服務器發(fā)送 ACK 報文,生成一個序列號 SEQ=u+1;由于回復的是服務器,所以 ACK 字段的值在服務器發(fā)來斷開 TCP 連接請求序列號 SEQ=w 的基礎上加 1,得到 ack=w+1
此時,客戶端就進入了TIME_WAIT (時間等待) 狀態(tài);注意此時TCP連接還沒有釋放,必須經(jīng)過2MSL (最長報文段壽命) 的時間后,當客戶端撤銷相應的TCB后,才進入CLOSED狀態(tài)
兩個重要的狀態(tài):
- CLOSE_WAIT: 表示在等待關(guān)閉; 四次揮手揮了一半了,當前可能剩下的兩次不揮了(接收方?jīng)]調(diào)用 close 方法,就會導致四次揮手只揮兩次,從而沒有正確關(guān)閉連接)
- TIME_WAIT: 誰主動斷開連接,誰進入 TIME-WAIT 狀態(tài),此時該主機已經(jīng)完成了四次揮手的過程,但仍不能立刻斷開連接,而是要以 TIME-WAIT 狀態(tài)來保持連接一段時間之后,再徹底釋放連接 (處理最后一個 ACK 丟包之后重傳的問題)
為了解決網(wǎng)絡的丟包和網(wǎng)絡不穩(wěn)定所帶來的其他問題,確保連接方能在時間范圍內(nèi),關(guān)閉自己的連接
1.四次揮手,三次揮完行不行??
通常情況下不行,若觸發(fā)了延時應答機制,就可以三次揮完
"不行",即:上述的 ② ③ 為什么沒有合并在一起??
因為中間兩次操作的時機不一樣
ACK 是收到 FIN 之后立刻由內(nèi)核返回的數(shù)據(jù)報,FIN 是應用程序處理完接受緩沖區(qū)的數(shù)據(jù)之后,調(diào)用的 close 方法觸發(fā)的
.
2.為什么四次??
因為要確保客戶端和服務端的數(shù)據(jù)能夠完成傳輸
.
3.為什么 TIME_WAIT 狀態(tài)要等待 2MSL??
假設網(wǎng)絡上傳輸數(shù)據(jù)的最大時間為 MSL
MSL 就是 ACK / FIN 從主機 A 到主機 B 的最大時間
TIME-WAIT 等待時間,需要分成兩個部分:
①等待 ACK 經(jīng)歷一個最大時間到達主機 B
②萬一 ACK 丟了,在等待一個最大時間,主機 B 重傳 FIN 到達主機 A
因此,TIME_WAIT 就需要等待 2倍的MSL,即:2MSL
原因:
- 確保 ACK 報文能夠到達服務端,從而使服務端正常關(guān)閉連接
第四次揮手時,客戶端第四次揮手的 ACK 報文不一定會到達服務端;服務端會超時重傳 FIN / ACK 報文,此時如果客戶端已經(jīng)斷開了連接,那么就無法響應服務端的二次請求,這樣服務端遲遲收不到 FIN / ACK 報文的確認,就無法正常斷開連接
MSL 是報文段在網(wǎng)絡上存活的最長時間,客戶端等待 2MSL 時間,即「客戶端 ACK 報文 1MSL 超時 + 服務端 FIN 報文 1MSL 傳輸」,就能夠收到服務端重傳的 FIN / ACK 報文,然后客戶端重傳一次 ACK 報文,并重新啟動 2MSL 計時器;如此保證服務端能夠正常關(guān)閉
如果服務端重發(fā)的 FIN 沒有成功地在 2MSL 時間里傳給客戶端,服務端則會繼續(xù)超時重試直到斷開連接 - 防止已失效的連接請求報文段出現(xiàn)在之后的連接中
TCP 要求在 2MSL 內(nèi)不使用相同的序列號;客戶端在發(fā)送完最后一個 ACK 報文段后,再經(jīng)過時間 2MSL,就可以保證本連接持續(xù)的時間內(nèi)產(chǎn)生的所有報文段都從網(wǎng)絡中消失;這樣就可以使下一個連接中不會出現(xiàn)這種舊的連接請求報文段;或者即使收到這些過時的報文,也可以不處理它
總結(jié)
以上是生活随笔為你收集整理的TCP 协议(包含三次握手,四次挥手)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C程序设计语言(KR)笔记
- 下一篇: 用友NC移动审批