TCP
的三次握手🤝創建鏈接和四次揮手👋斷開鏈接,相信不少人都據說過,也都看過相關的內容,本篇是爲了記錄本身對與這兩種操做的理解。html
在進入正式內容以前,先來看幾個符號的概念:安全
序列號seq
: 用來標記數據段的順序,TCP
把鏈接中發送的全部數據字節都編上一個序號,第一個字節的編號由本地隨機產生;給字節編上序號後,就給每個報文段指派一個序號;序列號seq
就是這個報文段中的第一個字節的數據編號。服務器
確認號ack
: 期待收到對方下一個報文段的第一個數據字節的序號;序列號表示報文段攜帶數據的第一個字節的編號;而確認號指的是指望接收到下一個字節的編號;所以當前報文段最後一個字節的編號+1即爲確認號。網絡
確認ACK
: 僅當ACK=1
時,確認號字段纔有效。ACK=0
時,確認號無效工具
同步SYN
: 鏈接創建時用於同步序號。當SYN=1
,ACK=0
時表示:這是一個鏈接請求報文段。若贊成鏈接,則在響應報文段中使得SYN=1
,ACK=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=1
,SYN=1
,確認號是ack=x+1
,同時也要爲本身隨機初始化一個序列號 seq=y
,此時,服務器進程進入了SYN-RCVD
狀態,詢問客戶端是否作好準備。ACK=1
,ack=y+1
,此時,鏈接創建,客戶端進入ESTABLISHED
狀態,服務器端也進入ESTABLISHED
狀態。以上就是三次握手🤝的一個大概流程,那麼問題來了:
握手🤝爲何須要三次呢,若是把最後一次的去掉改成兩次握手🤝是否可行呢?
假如如今客戶端想向服務端進行握手,它發送了第一個鏈接的請求報文,可是因爲網絡信號差或者服務器負載過多,這個請求沒有當即到達服務端,而是在某個網絡節點中長時間的滯留了,以致於滯留到客戶端鏈接釋放之後的某個時間點纔到達服務端,那麼這就是一個失效的報文,可是服務端接收到這個失效的請求報文後,就誤認爲客戶端又發了一次鏈接請求,服務端就會想向客戶端發出確認的報文,表示贊成創建鏈接。
假如不採用三次握手,那麼只要服務端發出確認,表示新的創建就鏈接了。可是如今客戶端並無發出創建鏈接的請求,其實這個請求是失效的請求,一切都是服務端在自相情願,所以客戶端是不會理睬服務端的確認信息,也不會向服務端發送確認的請求,可是服務器卻認爲新的鏈接已經創建起來了,並一直等待客戶端發來數據,這樣的狀況下,服務端的不少資源就沒白白浪費掉了。
採用三次握手的辦法就是爲了防止上述這種狀況的發生,好比就在剛纔的狀況下,客戶端不會向服務端發出確認的請求,服務端會由於收不到確認的報文,就知道客戶端並無要創建鏈接,那麼服務端也就不會去創建鏈接,這就是三次握手的做用。
來,再次進入如下情景:
假若有一天我想要自由了,我就跟個人女友提出分手的要求:
我:我要自由,自由萬歲,分手吧
女:好,你要分手是吧
而後她會罵我渣啊來發泄,或者試圖挽留,在通過冷靜以後:
女:那就這樣吧,分
我:好的,分
至此就各奔東西,互相安好,相忘於江湖。
當客戶端和服務器經過三次握手創建了TCP
鏈接之後,當數據傳送完畢,爲了防止資源浪費確定要斷開TCP
鏈接,那對於TCP
的斷開鏈接,這裏就有了斷開鏈接的四次揮手。
FIN=1
,其序列號爲seq=x
,此時,客戶端進入FIN-WAIT-1
(終止等待1)狀態。FIN
報文,發出確認ACK
報文,ACK=1
,ack=x+1
,而且帶上本身的序列號seq=y
,此時,服務端就進入了CLOSE-WAIT
(關閉等待)狀態。此時,服務端通知高層的應用進程,客戶端向服務端的方向就釋放了,這時候處於半關閉狀態,即客戶端已經沒有數據要發送了,可是服務端若發送數據,客戶端依然要接受。這個狀態還要持續一段時間,也就是整個CLOSE-WAIT
狀態持續的時間。客戶端收到服務端的確認請求後,此時,客戶端就進入FIN-WAIT-2
(終止等待2)狀態,等待服務器發送鏈接釋放報文,在這以前依然能夠接收服務端發送過來的最後的數據。FIN
報文,FIN=1
,ack=x+1
,此時的序列號爲seq=z
,此時,服務端就進入了LAST-ACK
(最後確認)狀態,等待客戶端的確認。FIN
報文後,必須發出確認報文,ACK=1
,ack=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
安裝完成以後,打開Wireshark
,開始監測網絡封包。
打開兩個終端窗口,創建一個鏈接(這裏很簡單,就不截圖了):
在終端窗口1中,輸入:nc -l 6060
回車
在終端窗口2中,輸入:nc 127.0.0.1 6060
回車
兩個終端創建鏈接以後,能夠在Wireshark
中看到三次握手的過程:
下面斷開鏈接再來看一下四次揮手的過程:
TCP
的三次握手和四次揮手,我的以爲其實就是在創建鏈接和斷開鏈接的時候,保證這個鏈接的「安全完整」。同時也保證了數據的完整發送。至此關於TCP
的三次握手和四次揮手就寫到這裏,若有錯誤還請指正!
以上情景劇內容純屬虛構,畢竟,真正的車手是不需女人的。(滑稽保命)