iOS:爲何TCP鏈接要三次握手,四次揮手

前言

TCP的三次握手🤝創建鏈接和四次揮手👋斷開鏈接,相信不少人都據說過,也都看過相關的內容,本篇是爲了記錄本身對與這兩種操做的理解。html

在進入正式內容以前,先來看幾個符號的概念:安全

  • 序列號seq 用來標記數據段的順序,TCP把鏈接中發送的全部數據字節都編上一個序號,第一個字節的編號由本地隨機產生;給字節編上序號後,就給每個報文段指派一個序號;序列號seq就是這個報文段中的第一個字節的數據編號。服務器

  • 確認號ack 期待收到對方下一個報文段的第一個數據字節的序號;序列號表示報文段攜帶數據的第一個字節的編號;而確認號指的是指望接收到下一個字節的編號;所以當前報文段最後一個字節的編號+1即爲確認號。網絡

  • 確認ACK 僅當ACK=1時,確認號字段纔有效。ACK=0時,確認號無效工具

  • 同步SYN 鏈接創建時用於同步序號。當SYN=1ACK=0時表示:這是一個鏈接請求報文段。若贊成鏈接,則在響應報文段中使得SYN=1ACK=1。所以,SYN=1表示這是一個鏈接請求,或鏈接接受報文。SYN這個標誌位只有在TCP建產鏈接時纔會被置1,握手完成後SYN標誌位被置0。code

  • 終止FIN 用來釋放一個鏈接。FIN=1表示:此報文段的發送方的數據已經發送完畢,並要求釋放運輸鏈接cdn

三次握手

首先進入一下情景:htm

我正在飯店裏和朋友吃飯,喝的正嗨的時候,女友打電話過來,飯店裏有不少人,環境緣由聽不太清電話裏的聲音:blog

我:能聽到個人聲音嗎?進程

女:能聽到,大點聲,你能聽到我講話嗎?

我:能聽到,

如此這般,才能保證雙方都能聽到聲音,才能繼續對話呀。

TCP是面向鏈接的,不管哪一方向另外一方發送數據以前,都必須先在雙方之間創建一條鏈接。在TCP/IP協議中,TCP 協議提供可靠的鏈接服務,鏈接是經過三次握手🤝進行初始化的。三次握手🤝的目的是同步鏈接雙方的序列號和確認號並交換 TCP窗口大小信息。由此咱們來對應客戶端與服務器之間的創建鏈接:

  • 第一次握手🤝: 客戶端向服務器發出鏈接請求報文,這時報文首部中的同部位SYN=1,同時隨機生成初始序列號 seq=x,此時,客戶端進程進入了 SYN-SENT狀態,等待服務器的確認。
  • 第二次握手🤝: 服務器收到請求報文後,若是贊成鏈接,則發出確認報文。確認報文中應該 ACK=1SYN=1,確認號是ack=x+1,同時也要爲本身隨機初始化一個序列號 seq=y,此時,服務器進程進入了SYN-RCVD狀態,詢問客戶端是否作好準備。
  • 第三次握手🤝: 客戶端進程收到確認後,還要向服務器給出確認。確認報文的ACK=1ack=y+1,此時,鏈接創建,客戶端進入ESTABLISHED狀態,服務器端也進入ESTABLISHED狀態。

以上就是三次握手🤝的一個大概流程,那麼問題來了:

握手🤝爲何須要三次呢,若是把最後一次的去掉改成兩次握手🤝是否可行呢?

假如如今客戶端想向服務端進行握手,它發送了第一個鏈接的請求報文,可是因爲網絡信號差或者服務器負載過多,這個請求沒有當即到達服務端,而是在某個網絡節點中長時間的滯留了,以致於滯留到客戶端鏈接釋放之後的某個時間點纔到達服務端,那麼這就是一個失效的報文,可是服務端接收到這個失效的請求報文後,就誤認爲客戶端又發了一次鏈接請求,服務端就會想向客戶端發出確認的報文,表示贊成創建鏈接。

假如不採用三次握手,那麼只要服務端發出確認,表示新的創建就鏈接了。可是如今客戶端並無發出創建鏈接的請求,其實這個請求是失效的請求,一切都是服務端在自相情願,所以客戶端是不會理睬服務端的確認信息,也不會向服務端發送確認的請求,可是服務器卻認爲新的鏈接已經創建起來了,並一直等待客戶端發來數據,這樣的狀況下,服務端的不少資源就沒白白浪費掉了。

採用三次握手的辦法就是爲了防止上述這種狀況的發生,好比就在剛纔的狀況下,客戶端不會向服務端發出確認的請求,服務端會由於收不到確認的報文,就知道客戶端並無要創建鏈接,那麼服務端也就不會去創建鏈接,這就是三次握手的做用。

四次揮手

來,再次進入如下情景:

假若有一天我想要自由了,我就跟個人女友提出分手的要求:

我:我要自由,自由萬歲,分手吧

女:好,你要分手是吧

而後她會罵我渣啊來發泄,或者試圖挽留,在通過冷靜以後:

女:那就這樣吧,分

我:好的,分

至此就各奔東西,互相安好,相忘於江湖。

當客戶端和服務器經過三次握手創建了TCP鏈接之後,當數據傳送完畢,爲了防止資源浪費確定要斷開TCP鏈接,那對於TCP的斷開鏈接,這裏就有了斷開鏈接的四次揮手。

  • 第一次揮手👋: 客戶端進程發出鏈接釋放FIN報文,而且中止發送數據。釋放數據報文首部,FIN=1,其序列號爲seq=x,此時,客戶端進入FIN-WAIT-1(終止等待1)狀態。
  • 第二次揮手👋: 服務端進程收到鏈接釋放FIN報文,發出確認ACK報文,ACK=1ack=x+1,而且帶上本身的序列號seq=y,此時,服務端就進入了CLOSE-WAIT(關閉等待)狀態。此時,服務端通知高層的應用進程,客戶端向服務端的方向就釋放了,這時候處於半關閉狀態,即客戶端已經沒有數據要發送了,可是服務端若發送數據,客戶端依然要接受。這個狀態還要持續一段時間,也就是整個CLOSE-WAIT狀態持續的時間。客戶端收到服務端的確認請求後,此時,客戶端就進入FIN-WAIT-2(終止等待2)狀態,等待服務器發送鏈接釋放報文,在這以前依然能夠接收服務端發送過來的最後的數據。
  • 第三次揮手👋: 服務端將最後的數據發送給客戶端完成後,就向客戶端發送鏈接釋放FIN報文,FIN=1ack=x+1,此時的序列號爲seq=z,此時,服務端就進入了LAST-ACK(最後確認)狀態,等待客戶端的確認。
  • 第四次揮手👋: 客戶端接收到服務端的鏈接釋放FIN報文後,必須發出確認報文,ACK=1ack=z+1,而本身的序列號是seq=x+1,此時,客戶端就進入了TIME-WAIT(時間等待)狀態。此時服務端收到客戶端發送過來的確認報文,就當即撤銷本身的傳輸控制塊TCB,進入CLOSED狀態,注意此時的TCP鏈接尚未釋放,必須通過2MSL(最長報文段壽命)的時間後,客戶端沒有收到服務端發來的任何數據,證實服務端已正常關閉,此時客戶端會撤銷相應傳輸控制塊TCB後,進入CLOSED狀態。至此,TCP的鏈接才真正的斷開了。(服務端結束TCP鏈接的時間要比客戶端稍微早一些)

好的,那麼問題又來了:

爲何斷開鏈接須要四次揮手👋呢,像創建鏈接的時候同樣,三次行不行呢?

TCP協議是一種面向鏈接的、可靠的、基於字節流的運輸層通訊協議。TCP是全雙工 模式,這就意味着,在客戶端想要斷開鏈接時,客戶端向服務端發送FIN報文,只是表示客戶端已經沒有數據要發送了,可是這個時候客戶端仍是能夠接收來自服務端的數據。

當服務端接收到FIN報文,並返回ACK報文,表示服務端已經知道了客戶端要斷開鏈接,客戶端已經沒有數據要發送了,可是這個時候服務端可能依然有數據要傳輸給客戶端。

當服務端的數據傳輸完以後,服務端會發送FIN報文給客戶端,表示服務端也沒有數據要傳輸了,服務端贊成關閉鏈接,以後,客戶端收到FIN報文,當即發送給客戶端一個ACK報文,肯定關閉鏈接。在以後,客戶端和服務端彼此就愉快的斷開了此次的TCP鏈接。

或許會有疑問,爲何服務端的ACK報文和FIN報文都是分開發送的,可是在三次握手的時候倒是ACK報文和SYN報文是一塊兒發送的,由於在三次握手的過程當中,當服務端收到客戶端的SYN鏈接請求報文後,能夠直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。可是在關閉鏈接時,當服務端接收到FIN報文時,極可能並不會當即關閉SOCKET,因此只能先回復一個ACK報文,告訴客戶端,你發的FIN報文我收到了,只有等到服務端全部的數據都發送完了,才能發送FIN報文,所以ACK報文和FIN報文不能一塊兒發送。因此斷開鏈接的時候才須要四次揮手來完成。

驗證

下面經過Wireshark抓包工具來抓包看一下三次握手和四次揮手:

工具:Wireshark

下載地址 www.pc6.com/mac/112232.…

安裝完成以後,打開Wireshark ,開始監測網絡封包。

打開兩個終端窗口,創建一個鏈接(這裏很簡單,就不截圖了):

在終端窗口1中,輸入:nc -l 6060 回車

在終端窗口2中,輸入:nc 127.0.0.1 6060 回車

兩個終端創建鏈接以後,能夠在Wireshark中看到三次握手的過程:

下面斷開鏈接再來看一下四次揮手的過程:

若是對照前面的三次握手和四次揮手的過程圖來看的話,更能明白此處的抓包到的數據。

總結

TCP的三次握手和四次揮手,我的以爲其實就是在創建鏈接和斷開鏈接的時候,保證這個鏈接的「安全完整」。同時也保證了數據的完整發送。至此關於TCP的三次握手和四次揮手就寫到這裏,若有錯誤還請指正!

以上情景劇內容純屬虛構,畢竟,真正的車手是不需女人的。(滑稽保命)

相關文章
相關標籤/搜索