TCP協議簡介
TCP協議是五層協議中運輸層的協議,下面依賴網絡層、鏈路層、物理層,對於一個報文想發到另一台機器(假設是服務器)上對等層,每一個所依賴的層都會對報文進行包裝,例如TCP協議就依賴網絡層的IP協議,所以發送的報文會經過如下封裝:
當這個數據包到達服務器時,服務器的網絡層會對IP相關協議內容解封裝、校驗,然后運輸層對TCP層進行解封,解封涉及到一系列的步驟,例如這個數據包是要干嘛?是發給我的嗎?這些操作需要根據TCP報文的首部信息來判斷,首部包含以下內容:
主要通過首部信息來了解這個包是干嘛的,關於首部信息,這兒需要用到的幾個如下:
ACK : TCP協議規定,只有ACK=1時有效,也規定連接建立后所有發送的報文的ACK必須為1
SYN(SYNchronization) : 在連接建立時用來同步序號。當SYN=1而ACK=0時,表明這是一個連接請求報文。對方若同意建立連接,則應在響應報文中使SYN=1和ACK=1. 因此, SYN置1就表示這是一個連接請求或連接接受報文。
FIN (finis)即完,終結的意思, 用來釋放一個連接。當 FIN = 1 時,表明此報文段的發送方的數據已經發送完畢,並要求釋放連接。
注意:URG、ACK、PSH、PST、RST、SYN、FIN只有一位,也就是只有0或者1兩種狀態。
TCP協議三次握手
下面這張圖不是本人畫的,如果作者看到可以聯系我為圖片設置您博文的外連接。
第一次握手,客戶端先向服務端發送一個請求連接的報文段,這個報文段SYN
位設置為1,序列號Seq(Sequence Number)
設置為某一值,假設為X,發送出去之后客戶端進入SYN_SEND
狀態,等待服務器的確認;
第二次握手:服務器收到SYN
報文段。服務器收到客戶端的SYN
報文段,需要對這個SYN
報文段進行確認,設置Acknowledgment Number為x+1(Sequence Number+1);
同時,自己自己還要發送SYN請求信息,將SYN
位置為1,Sequence Number
為y;服務器端將上述所有信息放到一個報文段(即SYN+ACK
報文段)中,一並發送給客戶端,此時服務器進入SYN_RECV
狀態;
第三次握手:客戶端收到服務器的SYN+ACK報文段。然后將Acknowledgment Number
設置為y+1,向服務器發送ACK報文段,這個報文段發送完畢以后,客戶端和服務器端都進入ESTABLISHED
狀態,完成TCP三次握手。
完成了三次握手,客戶端和服務器端就可以開始傳送數據。以上就是TCP三次握手的總體介紹。
為什么要三次握手而不是兩次?
為什么非要進行三次連接呢?兩次行嗎?在謝希仁的《計算機網絡》中是這樣說的:
為了防止已失效的連接請求報文段突然又傳送到了服務端,因而產生錯誤。如下:
“已失效的連接請求報文段”的產生在這樣一種情況下:client
發出的第一個連接請求報文段並沒有丟失,而是在某個網絡結點長時間的滯留了,以致延誤到連接釋放以后的某個時間才到達server
。本來這是一個早已失效的報文段。但server收到此失效的連接請求報文段后,就誤認為是client再次發出的一個新的連接請求。於是就向client發出確認報文段,同意建立連接。假設不采用“三次握手”,那么只要server發出確認,新的連接就建立了。由於現在client並沒有發出建立連接的請求,因此不會理睬server的確認,也不會向server發送數據。但server卻以為新的運輸連接已經建立,並一直等待client發來數據。這樣,server的很多資源就白白浪費掉了。采用“三次握手”的辦法可以防止上述現象發生。例如剛才那種情況,client不會向server的確認發出確認。server由於收不到確認,就知道client並沒有要求建立連接。”,防止了服務器端的一直等待而浪費資源。
第三次握手失敗了怎么辦?
在tcp三次握手中 第二次握手完成后connect 就成功返回了 如果第三次握手的ack包丟了 此時 客戶端已認為連接是成功的,如果沒有應用層的心跳包,客戶端會一直維護這個連接 請問如何避免這種情況?
第二次握手服務器收到SYN包,然后發出SYN+ACK數據包確認收到並且請求建立連接,服務器進入SYN_RECV狀態。而這個時候第三次握手時客戶端發送ACK給服務器失敗了,服務器沒辦法進入ESTABLISH狀態,這個時候肯定不能傳輸數據的,不論客戶端主動發送數據與否,服務器都會有定時器發送第二步SYN+ACK數據包,如果客戶端再次發送ACK成功,建立連接。
如果一直不成功,服務器肯定會有超時(大概64s)設置,超時之后會給客戶端發RTS報文(連接重置),進入CLOSED狀態,防止SYN洪泛攻擊,這個時候客戶端應該也會關閉連接。
SYN洪泛攻擊:
SYN攻擊利用的是TCP的三次握手機制,攻擊端利用偽造的IP地址向被攻擊端發出請求,而被攻擊端發出的響應 報文將永遠發送不到目的地,那么被攻擊端在等待關閉這個連接的過程中消耗了資源,如果有成千上萬的這種連接,主機資源將被耗盡,從而達到攻擊的目的。
TCP協議四次分手
還是這個圖鎮帖:
四次分手,意思是某一端(可以使客戶端,也可以是服務器端)想結束會話斷開連接,那么具體流程是:
第一次分手:主機1,設置序列號Seq(Sequence Number)
和確認包ACK(Acknowledgment Number)
,假設seq為x+2,ACK=y+1,再將FIN標志位設置為1,向主機2發送FIN報文段;之后主機1進入FIN_WAIT_1
狀態;這表示主機1沒有數據要發送給主機2了;
第二次分手:主機2收到了主機1發送的FIN報文段,向主機1回一個ACK
報文段(其值為接收到的FIN報文的seq值+1);主機1進入FIN_WAIT_2
狀態,等待主機二的斷開請求包FIN;
第三次分手:主機2向主機1發送FIN
報文段,意思是我可以斷開連接了,請求關閉連接,同時主機2進入CLOSE_WAIT
狀態;
第四次分手:主機1收到主機2發送的FIN
報文段,向主機2發送ACK
報文段,值為剛剛接收到的FIN包Seq值+1,然后主機1進入TIME_WAIT
狀態;主機2收到主機1的ACK
報文段以后,就關閉連接;此時,主機1等待2MSL
后依然沒有收到回復,則證明Server端已正常關閉,那好,主機1也可以關閉連接了。
為什么要四次揮手
TCP是全雙工模式,這就意味着,當主機1發出FIN
報文段時,只是表示主機1已經沒有數據要發送了,主機1告訴主機2,它的數據已經全部發送完畢了;但是,這個時候主機1還是可以接受來自主機2的數據;當主機2返回ACK
報文段時,表示它已經知道主機1沒有數據發送了,但是主機2還是可以發送數據到主機1的;當主機2也發送了FIN
報文段時,這個時候就表示主機2也沒有數據要發送了,就會告訴主機1,我也沒有數據要發送了,之后彼此就會愉快的中斷這次TCP連接。如果要正確的理解四次分手的原理,就需要了解四次分手過程中的狀態變化。
四次揮手狀態解釋
FIN_WAIT_1
: 這個狀態要好好解釋一下,其實FIN_WAIT_1
和FIN_WAIT_2
狀態的真正含義都是表示等待對方的FIN
報文。而這兩種狀態的區別是:FIN_WAIT_1
狀態實際上是當SOCKET在ESTABLISHED
狀態時,它想主動關閉連接,向對方發送了FIN
報文,此時該SOCKET即進入到FIN_WAIT_1
狀態。也就是,發出FIN包之后進入FIN_WAIT_1狀態
而當對方回應ACK
報文后,則進入到FIN_WAIT_2
狀態,當然在實際的正常情況下,無論對方何種情況下,都應該馬上回應ACK
報文,所以FIN_WAIT_1
狀態一般是比較難見到的,而FIN_WAIT_2
狀態還有時常常可以用netstat看到。也就是,發出ACK報文之后進入FIN_WAIT_2狀態
主動方FIN_WAIT_2
:上面已經詳細解釋了這種狀態,實際上FIN_WAIT_2
狀態下的SOCKET,表示半連接,也即有一方要求close
連接,但另外還告訴對方,我暫時還有點數據需要傳送給你(ACK
信息),稍后再關閉連接。
主動方CLOSE_WAIT
:這種狀態的含義其實是表示在等待關閉。怎么理解呢?當對方close一個SOCKET后發送FIN
報文給自己,你系統毫無疑問地會回應一個ACK
報文給對方,此時則進入到CLOSE_WAIT
狀態。接下來呢,實際上你真正需要考慮的事情是察看你是否還有數據發送給對方,如果沒有的話,那么你也就可以 close這個SOCKET,發送FIN
報文給對方,也即關閉連接。所以你在CLOSE_WAIT
狀態下,需要完成的事情是等待你去關閉連接。
被動方LAST_ACK
: 這個狀態還是比較容易好理解的,它是被動關閉一方在發送FIN
報文后,最后等待對方的ACK
報文。當收到ACK
報文后,也即可以進入到CLOSED
可用狀態了。也就是接收到了對方的FIN包,自己發出了ACK以及FIN包之后的狀態
被動方TIME_WAIT
: 表示收到了對方的FIN
報文,並發送出了ACK
報文,就等2MSL
后即可回到CLOSED
可用狀態了。如果FIN_WAIT1
狀態下,收到了對方同時帶FIN
標志和ACK
標志的報文時,可以直接進入到TIME_WAIT
狀態,而無須經過FIN_WAIT_2
狀態。
主動方CLOSED
: 表示連接中斷。
TCP狀態圖
狀態圖解釋
- CLOSED:起始點,在超時或者連接關閉時候進入此狀態。
- LISTEN:svr端在等待連接過來時候的狀態,svr端為此要調用socket, bind,listen函數,就能進入此狀態。此稱為應用程序被動打開(等待客戶端來連接)。
- SYN_SENT:客戶端發起連接,發送SYN給服務器端。如果服務器端不能連接,則直接進入CLOSED狀態。
- SYN_RCVD:跟3對應,服務器端接受客戶端的SYN請求,服務器端由LISTEN狀態進入SYN_RCVD狀態。同時服務器端要回應一個ACK,同時發送一個SYN給客戶端;另外一種情況,客戶端在發起SYN的同時接收到服務器端得SYN請求,客戶端就會由SYN_SENT到SYN_RCVD狀態。
- ESTABLISHED:服務器端和客戶端在完成3次握手進入狀態,說明已經可以開始傳輸數據了。
以上是建立連接時服務器端和客戶端產生的狀態轉移說明。相對來說比較簡單明了,如果你對三次握手比較熟悉,建立連接時的狀態轉移還是很容易理解。接下來服務器端和客戶端就進行數據傳輸。。。。,當然,里面也大有學問,就此打住,稍后再表。下面,我們來看看連接關閉時候的狀態轉移說明,關閉需要進行4次雙方的交互,還包括要處理一些善后工作(TIME_WAIT狀態),注意,這里主動關閉的一方或被動關閉的一方不是指特指服務器端或者客戶端,是相對於誰先發起關閉請求來說的: - FIN_WAIT_1:主動關閉的一方,由狀態5進入此狀態。具體的動作時發送FIN給對方。
- FIN_WAIT_2:主動關閉的一方,接收到對方的FIN ACK,進入此狀態。由此不能再接收對方的數據。但是能夠向對方發送數據。
- CLOSE_WAIT:接收到FIN以后,被動關閉的一方進入此狀態。具體動作時接收到FIN,同時發送ACK。
- LAST_ACK:被動關閉的一方,發起關閉請求,由狀態8進入此狀態。具體動作時發送FIN給對方,同時在接收到ACK時進入CLOSED狀態。
- CLOSING:兩邊同時發起關閉請求時,會由FIN_WAIT_1進入此狀態。具體動作是,接收到FIN請求,同 時響應一個ACK。
- TIME_WAIT:最糾結的狀態來了。從狀態圖上可以看出,有3個狀態可以轉化成它,我們一一來分析:
a.由FIN_WAIT_2進入此狀態:在雙方不同時發起FIN的情況下,
主動關閉的一方在完成自身發起的關閉請求后,接收到被動關閉一方的FIN后進入的狀態。
b.由CLOSING狀態進入:雙方同時發起關閉,都做了發起FIN的請求,
同時接收到了FIN並做了ACK的情況下,由CLOSING狀態進入。
c.由FIN_WAIT_1狀態進入:同時接受到FIN(對方發起),ACK(本身發起的FIN回應),
與b的區別在於本身發起的FIN回應的ACK先於對方的FIN請求到達,
而b是FIN先到達。這種情況概率最小。
關閉的4次連接最難理解的狀態是TIME_WAIT,存在TIME_WAIT的2個理由:
1.可靠地實現TCP全雙工連接的終止。
2.允許老的重復分節在網絡中消逝。