計算機網絡基礎:TCP協議之三次握手與四次揮手

上一篇裏,我們瞭解了傳輸層的TCP協議以及TCP協議實現的機制,接下來我們就來詳解一下TCP協議的連接管理機制:

連接管理

         TCP提供面向有連接的數據傳輸,面向有連接是指在數據通信開始之前先做好通信兩端之間的準備工作。

         也就是說TCP協議需要在客戶端與服務器成功連接之後纔可使用,那麼客戶端與服務器的連接過程是什麼呢?

  • TCP建立連接:三次揮手 (客戶端連接服務器需要完成三次握手
  • TCP斷開連接:四次揮手 (通信完畢過後斷開連接需要四次揮手

         三次握手與網絡通信之間的關係:

           

面試題:

        TCP三次握手的過程,accept發生在三次握手哪個階段?

  • 發生在三次握手後。

       

三次握手

  • 客戶端與服務器在握手之前都做了一些前期的準備。服務器在開始先分配一個描述符,然後填充一下sockaddr_in結構體,綁定創建的文件描述符及服務器端口,接着listen監聽,使得剛纔的文件描述符成爲一個監聽描述符,最後阻塞至accept等待客戶端的連接。而客戶端相較來說簡單一些,就是分配文件描述符,填充sockaddr_in結構體,最後進行connect請求服務器的連接,直至服務器響應。
  • 在客戶端經過connect請求服務器響應的時候,向服務器發送同步報文段也就是SYN請求,發送完畢後等待服務器響應。服務器如果收到了SYN同步報文段,那麼就會給客戶端發送ACK響應,意爲收到了客戶端發送的同步報文段,在此同時,服務器也會發送SYN同步報文段,請求客戶端的響應。客戶端在接收到SYN同步報文段後也會發送ACK響應來回復服務器。這個過程就是三次握手的過程
  • 這樣看來,客戶端與服務器的連接是雙方的,兩者都得發送請求同樣兩者也都得響應。圖上來看,SYN_SENT就是請求連接狀態,SYN_RCVD就是等待連接狀態。在三次握手成功後,服務器與客戶端都會進入ESTABLISHED狀態,也就是TCP連接成功態,這個時候就可以進行數據的傳送了。
  • 這個過程中如果客戶端的SYN請求如果丟包,服務器不會響應,而客戶端會有一個等待時間,等待時間到達,未收到ACK響應,這個時候客戶端會發起再次請求。如果多次請求都未成功,此時客戶端可能會判斷網絡異常,不會再次請求。同樣再服務器接收到客戶端的SYN請求之後也會發送ACK響應同時發送SYN請求。如果客戶端遲遲不給服務器ACK響應,服務器也會進行重發,直至判斷網絡異常。所以說,三次握手任意一個缺失都不會連接成功,也就無法通信。所以三次握手也是確保TCP可靠的一種方式。

 

四次揮手

         在客戶端與服務器通信完畢後,客戶端調用close,開始進行四次揮手:

  • 在客戶端與服務器數據傳輸完畢之後,客戶端沒有請求了,所以此時調用close關閉文件描述符,開始進入FIN_WAIT_1狀態,同時向服務器發送FIN結束報文段並等待服務器的響應。當服務器這裏收到了FIN結束報文段時,這個時候服務器進入CLOSE_WAIT狀態。並給客戶端進行應答發送ACK。當客戶端收到服務器的ACK響應時,進入FIN_WAIT_2狀態。當服務器調用close時,會向客戶端發送FIN結束報文段。此時進入LAST_ACK狀態。此時的客戶端收到服務器發送的FIN時,會向服務器進行響應ACK,並且客戶端進入TIME_WAIT狀態,TIME_WAIT結束之後,進入CLOSED,斷開連接成功。當服務器收到客戶端最後的ACK時,進入CLOSED狀態,斷開連接成功。
     

一、CLOSE_WAIT與LAST_ACK狀態:

1、在三次握手的時候服務器可以將SYN與ACK同時發送,但是爲什麼這裏服務器發送的FIN與ACK是分開發送的呢?

  • 首先FIN信號是由於調用close所以才發送的。而客戶端調用close時,發送FIN結束報文段並進入FIN_WAIT_1狀態。而這個報文段在服務器中用戶態其實是無法感知的,內核會自己處理這個報文段,也就是說由內核進行ACK響應。這個過程中不是由用戶代碼決定的,服務器的FIN是由用戶代碼調用close發送的,所以內核與服務器不一定是同時處理這個信息的。所以FIN與ACK不一定是同時發送出去的。(注意:這裏是不一定!!!但是三次握手的時候發送SYN是由內核直接完成的,所以這就可以達到一個同步發送的情況。)

2、若服務器的代碼沒有調用close,意味着並沒有發送FIN結束報文段。那麼此連接的服務器將會長期保持在CLOSE_WAIT狀態,這會有什麼影響? 

  • 服務器長期保持在CLOSE_WAIT狀態,也就是說分配的文件描述符並沒有關閉並歸還。那麼大量的CLOSE_WAIT存在的話,就會導致一種資源的泄漏可能到最後就沒有可分配的文件描述符了,那麼就會使一些客戶端無法連接,從而造成不可估量的影響。

二、TIME_WAIT狀態

1、TIME_WAIT的目的:

  • 確保連接正常釋放
  • 使之前發送的消息被接收完畢

2、在客戶端最後一次發送ACK響應後,進入TIME_WAIT狀態,而這個狀態的時候客戶端在做什麼呢? 

  • 此時客戶端在等待!在客戶端最後發送ACK響應後,進入TIME_WAIT狀態,這是爲了防止最後發送的ACK響應丟包。在這裏,TIME_WAIT狀態會等待2MSL的時間。
  • MSL(Max Segment Life):報文的最大生存時間,這裏的生存時間指的是一個報文從發生到被接收到的整個過程,這個過程的時間就是MSL。(Linux下可以利用cat /proc/sys/net/ipv4/tcp_fin_timeout來查看MSL的值) 

3、客戶端最後一次發送ACK響應後,爲什麼要等待2MSL呢?

  • 爲了確保最後一條ACK消息的到達。因爲客戶端在發送最後一條ACK響應後進入TIME_WAIT狀態,如果這條ACK報文丟失,那麼服務器在等待一個MSL的時間過後發現沒有收到ACK響應,那麼它會重新發送一條FIN報文。這樣一條ACK響應的時間加上重發的FIN的時間正好就是2MSL。如果客戶端等待2MSL後沒有收到FIN報文,那麼意味着服務器收到了客戶端發送的ACK報文,這樣就斷開連接。 

4、在TIME_WAIT的時候,客戶端與服務器之間的TCP連接還是存在的。

5、如何避免TIME_WAIT狀態?

  • 首先服務器可以設置SO_REUSEADDR套接字選項來通知內核,如果端口忙,但TCP連接位於TIME_WAIT狀態時可以重用端口。在一個非常有用的場景就是,如果你的服務器程序停止後想立即重啓,而新的套接字依舊希望使用同一端口,此時SO_REUSEADDR選項就可以避免TIME_WAIT狀態。

 

常見面試題:

  • 三次握手未完成時

答:當這三個過程沒有全部完成 被稱爲半連接狀態

  • 三次握手爲什麼必須是三次

答:防止延遲(已失效)的連接請求被服務器誤認爲是新連接,因此造成資源浪費或錯誤。

        (client發出的第一個連接請求報文段並沒有丟失,而是在某個網絡結點長時間的滯留了,以致延誤到連接釋放以後的某個時間纔到達server。本來這是一個早已失效的報文段。但server收到此失效的連接請求報文段後,就誤認爲是client再次發出的一個新的連接請求。於是就向client發出確認報文段,同意建立連接。假設不採用“三次握手”,那麼只要server發出確認,新的連接就建立了。由於現在client並沒有發出建立連接的請求,因此不會理睬server的確認,也不會向server發送數據。但server卻以爲新的運輸連接已經建立,並一直等待client發來數據。這樣,server的很多資源就白白浪費掉了。採用“三次握手”的辦法可以防止上述現象發生。例如剛纔那種情況,client不會向server的確認發出確認。server由於收不到確認,就知道client並沒有要求建立連接)

 

        總的來說:"3次握手”的作用就是雙方都能明確自己和對方的收、發能力是正常的。

       第一次握手:客戶端發送網絡包,服務端收到了。這樣服務端就能得出結論:客戶端的發送能力、服務端的接收能力是正常的。

       第二次握手:服務端發包,客戶端收到了。這樣客戶端就能得出結論:服務端的接收、發送能力,客戶端的接收、發送能力是正常的。 從客戶端的視角來看,我接到了服務端發送過來的響應數據包,說明服務端接收到了我在第一次握手時發送的網絡包,並且成功發送了響應數據包,這就說明,服務端的接收、發送能力正常。而另一方面,我收到了服務端的響應數據包,說明我第一次發送的網絡包成功到達服務端,這樣,我自己的發送和接收能力也是正常的。

       第三次握手:客戶端發包,服務端收到了。這樣服務端就能得出結論:客戶端的接收、發送能力,服務端的發送、接收能力是正常的。 第一、二次握手後,服務端並不知道客戶端的接收能力以及自己的發送能力是否正常。而在第三次握手時,服務端收到了客戶端對第二次握手作的迴應。從服務端的角度,我在第二次握手時的響應數據發送出去了,客戶端接收到了。所以,我的發送能力是正常的。而客戶端的接收能力也是正常的。

        經歷了上面的三次握手過程,客戶端和服務端都確認了自己的接收、發送能力是正常的。之後就可以正常通信了

  • 爲什麼連接的時候是三次握手,關閉的時候卻是四次揮手

答:因爲當Server端收到Client端的SYN連接請求報文後, 可以直接發送SYN+ACK報文,其中ACK報文是用來應答的,SYN報文是用來同步的。但是在關閉連接時,當Server端收到FIN報文時,很可能並不會立即關閉SOCKET,因爲服務器是否現在關閉發送數據通道還需要上層應用來決定,所以只能先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了"。只有等到我Server端所有的報文都發送完了,我才能發送FIN報文,因此不能一起發送。故需要四次揮手。總的來說,四次揮手的原因是:一方發送FIN只表示自己發完了所有要發的數據,但還允許對方繼續把沒發完的數據發過來。

  • 三次握手的目的是什麼

答:一是客戶端爲了確認服務器端此時在正常運行,二是爲了獲取序列號(ISN),以便讓對方知道接下來接收數據的時候如何按序列號組裝數據。

  • 若不進行四次揮手會出現什麼後果

答:浪費套接字資源,導致可用的套接字越來越少,進而使得服務器無法正常運行。

 

  • SYN泛洪攻擊   (針對三次握手,是TCP/IP協議的一個缺陷)

答:利用合理的服務請求來佔用過多的服務資源,從而使合法用戶無法得到服務的響應。syn flood屬於Dos 攻擊的一種。Dos攻擊發送無效的請求,使得正確的請求無法被響應。
       攻擊者會模擬大量的虛擬IP向服務器發送連接請求,但是服務器確認請求的時候也就是第二步的時候   得不到客戶端的迴應 因爲IP都是攻擊者模擬的不存在的IP, 這些請求長時間佔用未連接隊列導致正確的請求被丟棄或者運行緩慢,最終會引起主機運行緩慢甚至是耗盡資源而癱瘓,以此達到攻擊目的。
       惡意的向某個服務器端口發送大量的SYN包,則可以使服務器打開大量的半開連接,分配TCB,從而消耗大量的服務器資源,同時也使得正常的連接請求無法被相應。系統會爲此耗盡資源。

  • 避免SYN泛洪攻擊

答:延緩TCB分配方法
        消耗服務器資源主要是因爲當SYN數據報文一到達,系統立即分配TCB,從而佔用了資源。而SYN Flood 由於很難建立起正常連接,因此,當正常連接建立起來後再分配TCB則可以有效地減輕服務器資源的消耗,常見的方法是使用Syn Cache和Syn Cookie技術。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章