網路程式設計 TCP連線的斷開(四次揮手)

2021-09-02 12:58:03 字數 3180 閱讀 9792

上個部落格講解了tcp連線建立的全過程,以及其連線雙方的各個狀態,那麼連線斷開的時候又是什麼情況呢?

發起鏈結的主動方基本都是客戶端,但是斷開連線的主動方伺服器和客戶端都可以充當。

四次揮手是指斷開乙個tcp連線時,需要客戶端和服務端總共傳送4個包以確認連線的斷開。在socket程式設計中,這一過程由客戶端或服務端任一方執行close來觸發,整個流程如下圖所示:

由於tcp連線時全雙工的,因此,每個方向的資料傳輸通道都必須要單獨進行關閉。以上圖為例,主動斷開方完成資料傳送任務後,傳送乙個fin來終止從主動斷開方發給被動斷開方這一方向的連線,被動斷開方收到乙個fin只是意味著從主動斷開方發給自己的這一方向上沒有資料流動了,即自己不會再收到資料了,但是在這個tcp連線上仍然能夠傳送資料,可以由被動斷開方發給主動斷開方,直到這一方向也傳送了fin,連線才真正的完全關閉。

第一次揮手:

client傳送乙個fin(fin位為1),其序號seq=u,它等於前面已經傳送的資料的最後乙個位元組的序號+1。用來關閉client到server的資料傳送,然後client等待server的確認,client進入fin_wait_1狀態。(ps:fin報文段即便不攜帶資料還是佔乙個序號)

第二次揮手:

server收到fin後,傳送乙個ack給client,ack確認序號為收到序號+1(與syn相同,乙個fin占用乙個序號),這個確認報文段自己的序號是seq=v,它是server前面傳送過的資料的最後乙個位元組序號+1,然後server進入close_wait狀態。tcp的server程序通知高層應用程序,從client到server這個方向的連線關閉,這時tcp連線處於半關閉狀態,即client沒有資料傳送,但是server若要傳送資料,client仍要接收,即server到client這個方向的連線並未關閉。

第三次揮手:

server傳送乙個fin,用來關閉server到client的資料傳送,server進入last_ack狀態。

第四次揮手:

client收到fin後,client進入time_wait狀態,接著傳送乙個ack給server,確認序號為收到序號+1,server進入closed狀態,完成四次揮手。

上面是一方主動關閉,另一方被動關閉的情況,實際中還會出現同時發起主動關閉的情況,具體流程如下圖:

closing這種狀態在實際情況中應該很少見,屬於一種比較罕見的例外狀態。正常情況下,當一方傳送fin報文後,按理來說是應該先收到(或同時收到)對方的ack報文,再收到對方的fin報文。但是closing 狀態表示一方傳送fin報文後,並沒有先收到對方的ack報文,反而卻先收到了對方的fin報文。什麼情況下會出現此種情況呢?那就是上圖當雙方幾乎在同時close()乙個socket的話,就出現了雙方同時傳送fin報文的情況,這是就會出現closing 狀態,表示雙方都正在關閉socket連線。

總結:同時斷開時,如果主機在fin_wait1狀態下首先收到對端主機的fin包的話,那麼該主機在確認已經收到了對端主機全部的data資料報後,就響應乙個ack給對端主機,然後自己進入closeing狀態,主機在closeing狀態下收到自己的fin包的ack包的話,那麼就進入time wait 狀態。於是tcp的主機兩端同時發起fin包進行斷開連線,那麼兩端主機可能出現完全一樣的狀態轉移 fin_wait1——>closeing——->time_wait,也就會client和server最後同時進入time_wait狀態

如果主動關閉方不進入time_wait,那麼主動關閉方在傳送完ack就走了的話:如果最後傳送的ack在路由過程中丟掉了,最後沒能到被動關閉方,這個時候被動關閉方 沒收到自己fin的ack就不能關閉連線,接著被動關閉方 會超時重發fin包,但是這個時候已經沒有對端會給該fin回ack,被動關閉方就無法正常關閉連線了(雖然最後也會多次傳送斷開鏈結,但是浪費時間呀),所以主動關閉方需要進入time_wait 以便能夠重發丟掉的被動關閉方fin的ack。另一方面也是為了防止將本次鏈結的資料出現在下一次鏈結中。

(1)為了保證a傳送的最後乙個確認報文段能夠到達b。這個確認報文段可能會丟失,如果b收不到這個確認報文段,其會重傳第三次「揮手」傳送的fin+ack報文,而a則會在2msl時間內收到這個重傳的報文段,每次a收到這個重傳報文段後,就會重啟2msl計時器。這樣可以保證a和b都能正常關閉連線。

(2)為了防止被動方傳送的已失效的報文段出現在下一次連線中。a經過2msl時間後,可以保證在本次連線中傳輸的報文段都在網路中消失,這樣一來就能保證在後面的連線中不會出現舊的連線產生的報文段了。

time_wait帶來的問題注意是源於:乙個連線進入time_wait狀態後需要等待2*msl(一般是1到4分鐘)那麼長的時間才能斷開連線釋放連線占用的資源,會造成以下問題

(1)作為伺服器,短時間內關閉了大量的client連線,就會造成伺服器上出現大量的time_wait連線,佔據大量的tuple,嚴重消耗著伺服器的資源。

(2)作為客戶端,短時間內大量的短連線,會大量消耗的client機器的埠,畢竟埠只有65535個,埠被耗盡了,後續就無法在發起新的連線了。

使用rst包來終止掉處於time_wait狀態的鏈結,詳情可以看rst攻擊

tcp還設有乙個保活計時器,顯然,客戶端如果出現故障,伺服器不能一直等下去,白白浪費資源。伺服器每收到一次客戶端的請求後都會重新復位這個計時器,時間通常是設定為2小時,若兩小時還沒有收到客戶端的任何資料,伺服器就會傳送乙個探測報文段,以後每隔75分鐘傳送一次。若一連傳送10個探測報文仍然沒反應,伺服器就認為客戶端出了故障,接著就關閉連線。

tcp斷開連線四次揮手

tcp斷開連線是經歷了四次揮手的過程 1 客戶端主動斷開連線向服務端傳送 請求標誌位 fin 連線序號 seq 2 服務端收到請求後向客戶端傳送 確認請求標誌位 ack 確認連線序號 ack 3 服務端還會向客戶端傳送 請求標誌位 fin 連線序號 seq 4 客戶端在收到服務端資料後想服務端傳送 ...

TCP四次握手斷開連線

建立連線非常重要,它是資料正確傳輸的前提 斷開連線同樣重要,它讓計算機釋放不再使用的資源。如果連線不能正常斷開,不僅會造成資料傳輸錯誤,還會導致套接字不能關閉,持續占用資源,如果併發量高,伺服器壓力堪憂。建立連線需要三次握手,斷開連線需要四次握手,可以形象的比喻為下面的對話 下圖演示了客戶端主動斷開...

TCP斷開連線的四次揮手

之前學習了tcp建立連線的三次握手,現在來學習一下tcp斷開連線的四次揮手。簡單描述一下tcp斷開連線的原理。下面是我自己的理解圖。這裡是比較官方的圖。重點說一下各個狀態把 msl就是maximum segment lifetime 最大分節生命期 這是乙個ip資料報能在網際網路上生存的最長時間,超...