TCP的狀態簡介


 

TCP層

有個FLAGS字段,這個字段有以下幾個標識:SYN, FIN, ACK, PSH, RST, URG.

其中,對於我們日常的分析有用的就是前面的五個字段。

它們的含義是:

SYN:表示建立連接,

FIN:表示關閉連接,

ACK:表示響應,

PSH:表示有 DATA數據傳輸,

RST:表示連接重置。

狀態間的關系

其中,ACK是可能與SYN,FIN等同時使用的,比如SYN和ACK可能同時為1,它表示的就是建立連接之后的響應,

如果只是單個的一個SYN,它表示的只是建立連接。

TCP的幾次握手就是通過這樣的ACK表現出來的。

但SYN與FIN是不會同時為1的,因為前者表示的是建立連接,而后者表示的是斷開連接。

RST一般是在FIN之后才會出現為1的情況,表示的是連接重置。

一般地,當出現FIN包或RST包時,我們便認為客戶端與服務器端斷開了連接;而當出現SYN和SYN+ACK包時,我們認為客戶端與服務器建立了一個連接。

PSH為1的情況,一般只出現在 DATA內容不為0的包中,也就是說PSH為1表示的是有真正的TCP數據包內容被傳遞。

TCP的連接建立和連接關閉,都是通過請求-響應的模式完成的。

概念補充-TCP三次握手:

TCP(Transmission Control Protocol)傳輸控制協議

TCP是主機對主機層的傳輸控制協議,提供可靠的連接服務,采用三次握手確認建立一個連接:

位碼即tcp標志位,有6種標示:

SYN(synchronous建立聯機)

ACK(acknowledgement 確認)

PSH(push傳送) FIN(finish結束)

RST(reset重置)

URG(urgent緊急)

Sequence number(順序號碼)

Acknowledge number(確認號碼)

第一次握手:主機A發送位碼為syn=1,隨機產生seq number=1234567的數據包到服務器,主機B由SYN=1知道,A要求建立聯機;

第二次握手:主機B收到請求后要確認聯機信息,向A發送ack number=(主機A的seq+1),syn=1,ack=1,隨機產生seq=7654321的包;

第三次握手:主機A收到后檢查ack number是否正確,即第一次發送的seq number+1,以及位碼ack是否為1,若正確,主機A會再發送ack number=(主機B的seq+1),ack=1,主機B收到后確認seq值與ack=1則連接建立成功。

完成三次握手,主機A與主機B開始傳送數據。

 

在TCP/IP協議中

TCP協議提供可靠的連接服務,采用三次握手建立一個連接。

第一次握手:建立連接時,客戶端發送syn包(syn=j)到服務器,並進入SYN_SEND狀態,等待服務器確認;

第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;

第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手。完成三次握手,客戶端與服務器開始傳送數據

 

 

 

 

面試官問我TCP三次握手和四次揮手,我真的是

 

候選者面試官你好,請問面試可以開始了嗎

面試官:嗯,開始吧

面試官今天來聊聊TCP吧,TCP的各個狀態還有印象嗎?

候選者:還有些許印象的,要不我就來簡單說下TCP的三次握手和四次揮手的流程吧

候選者:說完這兩個流程,就能把TCP的狀態給涵蓋上了

面試官:可以吧

候選者:在說TCP的三次握手和四次揮手之前,我先給你畫下TCP的頭部格式唄(:

候選者:對於TCP三次握手和四次揮手,我們最主要的就是關注TCP頭部的序列號、確認號以及幾個標記位(SYN/FIN/ACK/RST)

候選者:序列號:在初次建立連接的時候,客戶端和服務端都會為「本次的連接」隨機初始化一個序列號。(縱觀整個TCP流程中,序列號可以用來解決網絡包亂序的問題)

候選者:確認號:該字段表示「接收端」告訴「發送端」對上一個數據包已經成功接收(確認號可以⽤來解決網絡包丟失的問題)

候選者:而標記位就很好理解啦。SYN為1時,表示希望創建連接。ACK為1時,確認號字段有效。FIN為1時,表示希望斷開連接。RST為1時,表示TCP連接出現異常,需要斷開。

候選者:下面就先從三次握手開始吧,期間我也會在三次握手中涉及到的TCP狀態也說下的。

候選者:TCP三次握手的過程其實就是在:確認通信雙方(客戶端和服務端)的序列號

候選者:它的過程是這樣的

候選者:在最開始的時候,客戶端和服務端都處於 CLOSE 狀態

候選者:服務器主動監聽某個端口,處於 LISTEN 狀態

候選者:客戶端會隨機生成出序列號(這里的序列號一般叫做client_isn),並且把標志位設置為SYN(意味着要連接),然后把該報文發送給服務端

候選者:客戶端發送完SYN報文以后,自己便進入了 SYN_SEND 狀態

候選者:服務端接收到了客戶端的請求之后,自己也初始化對應的序列號(這里的序列號一般叫做 server_isn)

候選者:在「確認號」字段里填上client_isn + 1(相當於告訴客戶端,已經收到了發送過來的序列號了) ,並且把 SYN 和 ACK 標記位都點亮(置為1)

候選者:把該報文發送客戶端,服務端的狀態變成 SYN-REVD 狀態

候選者:客戶端收到服務端發送的報文后,就知道服務端已經接收到了自己的序列號(通過確認號就可以知道),並且接收到了服務端的序列號(server_isn)

候選者:此時,客戶端需要告訴服務端自己已經接收到了他發送過來的序列號,所以在「確認號」字段上填上server_isn+1,,並且標記位 ACK 為1

候選者:客戶端在發送報文之后,進入 ESTABLISHED 狀態,而服務端接收到客戶端的報文之后,也進入 ESTABLISHED 狀態

候選者:這就是三次握手的過程以及涉及到的TCP狀態

候選者:總結下來,就是雙方都把自身的序列號發給對方,看對方能不能接收到。如果「確認可以」,那就可以正常通信。(三次握手這個過程就可以看到雙方都有接收和發送的能力)

面試官那兩次握手行嗎?

候選者:兩次握手只能保證客戶端的序列號成功被服務端接收,而服務端是無法確認自己的序列號是否被客戶端成功接收。所以是不行的(:

面試官了解了,那我想問問序列號為什么是隨機的?以及序列號是怎么生成的?

候選者:一方面為了安全性(隨機ISN能避免非同一網絡的攻擊),另一方面可以讓通信雙方能夠根據序號將「不屬於」本連接的報文段丟棄

候選者:序列號怎么生成的?這...隨便猜下就應該跟「時鍾」和TCP頭部的某些屬性做運算生成的吧,類似於雪花算法(:具體我忘了。

面試官既然網絡是不可靠的,那建立連接不是會經過三次握手嗎?那要是在中途丟了,怎么辦?

候選者:假設第一個包丟了,客戶端發送給服務端的 SYN 包丟了(簡而要之就是服務端沒接收到客戶端的SYN包)

候選者:客戶端遲遲收不到服務端的ACK包,那會周期性超時重傳,直到收到服務端的ACK

候選者:假設第二個包丟了,服務端發送的SYN+ACK包丟了(簡而要之就是客戶端沒接收到服務端的SYN+ACK包)

候選者:服務端遲遲收不到客戶端的ACK包,那會周期性超時重傳,直到收到客戶端的ACK

候選者:假設第三個包丟了(ACK包),客戶端發送完第三個包后單方面進入了 ESTABLISHED 狀態,而服務端也認為此時連接是正常的,但第三個包沒到達服務端

候選者:一、如果此時客戶端與服務端都還沒數據發送,那服務端會認為自己發送的SYN+ACK的包沒發送至客戶端,所以會超時重傳自己的SYN+ACK包

候選者:二、如果這時候客戶端已經要發送數據了,服務端接收到了ACK + Data數據包,那自然就切換到 ESTABLISHED 狀態下,並且接收客戶端的Data數據包

候選者:三、如果此時服務端要發送數據了,但發送不了,會一直周期性超時重傳SYN + ACK,直到接收到客戶端的ACK包

面試官嗯,是不是要講下四次揮手了?

候選者:嗯,在建立完連接之后,客戶端和服務端雙方都處於 ESTABLISHED 狀態狀態

候選者:斷開連接雙方都有權利的,下面我還是以客戶端主動斷開為例好啦。

候選者:客戶端打算關閉連接,會發 FIN 報文給服務端(其實就是把標志位 FIN 點亮),客戶端發送完之后,就進入FIN_WAIT_1狀態

候選者:服務端收到 FIN 報文之后,回復 ACK 報文給客戶端(表示已經收到了),服務端發送完之后,就進入 CLOSE_WAIT 狀態

候選者:客戶端接收到服務端的 ACK 報文,就進入了 FIN_WAIT_2 狀態

候選者:這時候,服務器可能還有數據要發送給客戶端,等服務端確認自己已經沒有數據返回給客戶端之后,就發送FIN報文給客戶端了,自己進入 LAST_ACK 狀態

候選者:客戶端收到服務端的FIN報文之后,回應ACK報文,自己進入 TIME_WAIT 狀態

候選者:服務端收到客戶端的ACK報文之后,服務端就進入 CLOSE 狀態

候選者:客戶端在TIME_WAIT等到2MSL,也進入了 CLOSE 狀態

候選者:四次揮手的流程到這里就結束了,結合三次握手,TCP的各個狀態也已經說完了。

面試官:嗯嗯,剛聊完四次揮手嘛,那你覺得為什么是四次呢?

候選者:其實很好理解,當客戶端第一次發送 FIN 報文之后,只是代表着客戶端不再發送數據給服務端,但此時客戶端還是有接收數據的能力的。而服務端收到FIN報文的時候,可能還有數據要傳輸給客戶端,所以只能先回復 ACK給客戶端

候選者:等到服務端不再有數據發送給客戶端時,才發送 FIN 報文給客戶端,表示可以關閉了。

候選者:所以,一來一回就四次了。

面試官從四次揮手的流程上來看,有個 TIME_WAIT 狀態,你知道這個狀態干什么用的嗎?(等待 2MSL)

候選者:主要有兩個原因吧。1.保證最后的 ACK 報文 「接收方」一定能收到(如果收不到,對方會 重發 FIN 報文)2. 確保在創建新連接時,先前網絡中殘余的數據都丟失了

候選者:其實也比較好理解的。就正如我們重啟服務器一樣,會先優雅關閉各種資源,再留有一段時間,希望在這段時間內,資源是正常關閉的,這樣重啟服務器(或者發布)就基本認為不會影響到線上運行了。

面試官假設 TIME_WAIT 狀態多過會有什么危害?怎么解決呢?

候選者:從流程上看, TIME_WAIT 狀態 只會出現在 主動發起 關閉連接的一方。危害就是會占用內存資源和端口唄(畢竟在等待嘛),解決的話,有Linux參數可以設置,具體忘了額。

面試官:今天最后再問個問題吧,我們常說TCP連接,那這個連接到底是什么?你是怎么理解的?

候選者:其實從三次握手可以發現的是,TCP建立連接無非就是交換了雙方的狀態(比如序列號)。然后就沒有然后了...連接本質上「只是互相維持一個狀態,有連接特性」

面試官:好吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM