TCP連線和斷開連線

2022-07-19 19:54:16 字數 3940 閱讀 1481

4.4、tcp資料報結構:

帶陰影的幾個字段需要重點說明一下:

(1) 序號:seq(sequence number)序號佔32位,用來標識從計算機a傳送到計算機b的資料報的序號,計算機傳送資料時對此進行標記。

(2) 確認號:ack(acknowledge number)確認號佔32位,客戶端和伺服器端都可以傳送,ack = seq + 1。

(3) 標誌位:每個標誌位占用1bit,共有6個,分別為 urg、ack、psh、rst、syn、fin,具體含義如下:

(1)urg:緊急指標(urgent pointer)有效。

(2)ack:確認序號有效。

(3)psh:接收方應該盡快將這個報文交給應用層。

(4)rst:重置連線。

(5)syn:建立乙個新連線。

(6)fin:斷開乙個連線。

4.5、連線的建立(三次握手):

使用 connect() 建立連線時,客戶端和伺服器端會相互傳送三個資料報,請看下圖:

客戶端呼叫 socket() 函式建立套接字後,因為沒有建立連線,所以套接字處於closed狀態;伺服器端呼叫 listen() 函式後,套接字進入listen狀態,開始監聽客戶端請求

這時客戶端發起請求:

1) 當客戶端呼叫 connect() 函式後,tcp協議會組建乙個資料報,並設定 syn 標誌位,表示該資料報是用來建立同步連線的。同時生成乙個隨機數字 1000,填充「序號(seq)」字段,表示該資料報的序號。完成這些工作,開始向伺服器端傳送資料報,客戶端就進入了syn-send狀態。

2) 伺服器端收到資料報,檢測到已經設定了 syn 標誌位,就知道這是客戶端發來的建立連線的「請求包」。伺服器端也會組建乙個資料報,並設定 syn 和 ack 標誌位,syn 表示該資料報用來建立連線,ack 用來確認收到了剛才客戶端傳送的資料報

伺服器生成乙個隨機數 2000,填充「序號(seq)」字段。2000 和客戶端資料報沒有關係。

伺服器將客戶端資料報序號(1000)加1,得到1001,並用這個數字填充「確認號(ack)」字段。

伺服器將資料報發出,進入syn-recv狀態

3) 客戶端收到資料報,檢測到已經設定了 syn 和 ack 標誌位,就知道這是伺服器發來的「確認包」。客戶端會檢測「確認號(ack)」字段,看它的值是否為 1000+1,如果是就說明連線建立成功。

接下來,客戶端會繼續組建資料報,並設定 ack 標誌位,表示客戶端正確接收了伺服器發來的「確認包」。同時,將剛才伺服器發來的資料報序號(2000)加1,得到 2001,並用這個數字來填充「確認號(ack)」字段。

客戶端將資料報發出,進入establised狀態,表示連線已經成功建立。

4) 伺服器端收到資料報,檢測到已經設定了 ack 標誌位,就知道這是客戶端發來的「確認包」。伺服器會檢測「確認號(ack)」字段,看它的值是否為 2000+1,如果是就說明連線建立成功,伺服器進入establised狀態。

至此,客戶端和伺服器都進入了establised狀態,連線建立成功,接下來就可以收發資料了。

4.6、tcp四次握手斷開連線

建立連線非常重要,它是資料正確傳輸的前提;斷開連線同樣重要,它讓計算機釋放不再使用的資源。如果連線不能正常斷開,不僅會造成資料傳輸錯誤,還會導致套接字不能關閉,持續占用資源,如果併發量高,伺服器壓力堪憂。

斷開連線需要四次握手,可以形象的比喻為下面的對話:

[shake 1] 套接字a:「任務處理完畢,我希望斷開連線。」

[shake 2] 套接字b:「哦,是嗎?請稍等,我準備一下。」

等待片刻後……

[shake 3] 套接字b:「我準備好了,可以斷開連線了。」

[shake 4] 套接字a:「好的,謝謝合作。」

下圖演示了客戶端主動斷開連線的場景:

建立連線後,客戶端和伺服器都處於establised狀態。這時,客戶端發起斷開連線的請求:

客戶端呼叫 close() 函式後,向伺服器傳送 fin 資料報,進入fin_wait_1狀態。fin 是 finish 的縮寫,表示完成任務需要斷開連線。

伺服器收到資料報後,檢測到設定了 fin 標誌位,知道要斷開連線,於是向客戶端傳送「確認包」,進入close_wait狀態。

注意:伺服器收到請求後並不是立即斷開連線,而是先向客戶端傳送「確認包」,告訴它我知道了,我需要準備一下才能斷開連線。

客戶端收到「確認包」後進入fin_wait_2狀態,等待伺服器準備完畢後再次傳送資料報。

等待片刻後,伺服器準備完畢,可以斷開連線,於是再主動向客戶端傳送 fin 包,告訴它我準備好了,斷開連線吧。然後進入last_ack狀態。

客戶端收到伺服器的 fin 包後,再向伺服器傳送 ack 包,告訴它你斷開連線吧。然後進入time_wait狀態。

伺服器收到客戶端的 ack 包後,就斷開連線,關閉套接字,進入closed狀態。

4.7、關於 time_wait 狀態的說明

客戶端最後一次傳送 ack包後進入 time_wait 狀態,而不是直接進入 closed 狀態關閉連線,這是為什麼呢?

tcp 是面向連線的傳輸方式,必須保證資料能夠正確到達目標機器,不能丟失或出錯,而網路是不穩定的,隨時可能會毀壞資料,所以機器a每次向機器b傳送資料報後,都要求機器b」確認「,回傳ack包,告訴機器a我收到了,這樣機器a才能知道資料傳送成功了。如果機器b沒有回傳ack包,機器a會重新傳送,直到機器b回傳ack包。

客戶端最後一次向伺服器回傳ack包時,有可能會因為網路問題導致伺服器收不到,伺服器會再次傳送 fin 包,如果這時客戶端完全關閉了連線,那麼伺服器無論如何也收不到ack包了,所以客戶端需要等待片刻、確認對方收到ack包後才能進入closed狀態。那麼,要等待多久呢?

資料報在網路中是有生存時間的,超過這個時間還未到達目標主機就會被丟棄,並通知源主機。這稱為報文最大生存時間(msl,maximum segment lifetime)。time_wait 要等待 2msl 才會進入 closed 狀態。ack 包到達伺服器需要 msl 時間,伺服器重傳 fin 包也需要 msl 時間,2msl 是資料報往返的最大時間,如果 2msl 後還未收到伺服器重傳的 fin 包,就說明伺服器已經收到了 ack 包

4.8.優雅的斷開連線–shutdown()

close()/closesocket()和shutdown()的區別

確切地說,close() / closesocket() 用來關閉套接字,將套接字描述符(或控制代碼)從記憶體清除,之後再也不能使用該套接字,與c語言中的 fclose() 類似。應用程式關閉套接字後,與該套接字相關的連線和快取也失去了意義,tcp協議會自動觸發關閉連線的操作。

shutdown() 用來關閉連線,而不是套接字,不管呼叫多少次 shutdown(),套接字依然存在,直到呼叫 close() / closesocket() 將套接字從記憶體清除。

呼叫 close()/closesocket() 關閉套接字時,或呼叫 shutdown() 關閉輸出流時,都會向對方傳送 fin 包。fin 包表示資料傳輸完畢,計算機收到 fin 包就知道不會再有資料傳送過來了。

預設情況下,close()/closesocket() 會立即向網路中傳送fin包,不管輸出緩衝區中是否還有資料,而shutdown() 會等輸出緩衝區中的資料傳輸完畢再傳送fin包。也就意味著,呼叫 close()/closesocket() 將丟失輸出緩衝區中的資料,而呼叫 shutdown() 不會

Tcp 斷開連線

tcp協議規定,對於已經建立的連線,網路雙方要進行四次握手才能成功斷開連線,如果缺少了其中某個步驟,將會使連線處於假死狀態,連線本身占用的資源不會被釋放。網路伺服器程式要同時管理大量連線,所以很有必要保證無用連線完全斷開,否則大量僵死的連線會浪費許多伺服器資源。在眾多tcp狀態中,最值得注意的狀態有...

TCP的連線和斷開

1.tcp的三次握手連線 l請求端 通常稱為客戶端 傳送乙個syn段指名客戶端打算連線的伺服器的埠,以及初始序號。序號 3662298720確認序號 0 l伺服器端發回包含伺服器的初始序號的 syn段,同時對客戶端的序號進行加1作為應答 序號 1139382973,確認序號 3662298721 l...

tcp連線和斷開流程

說起tcp,我們一般都需要知道發起乙個tcp連線和終止乙個tcp連線是所發生的事情,下邊,我將跟大家介紹下tcp的三次握手及四次揮手的過程。tcp三路握手 1 伺服器必須準備好接受外來的連線。這通常在呼叫socket,bind,listen這三個函式來完成,我們稱之為被動開啟 passive ope...