1. 程式人生 > >網路是怎樣連線的學習筆記-第二章-從伺服器斷開並刪除套接字

網路是怎樣連線的學習筆記-第二章-從伺服器斷開並刪除套接字

2.4 從伺服器斷開並刪除套接字

2.4.1 資料傳送完畢後斷開連線

收發資料結束的時間點應該是應用程式判斷所有資料都已經發送完畢的時候。

這時,資料傳送完畢的一方會發起斷開過程,但不同的應用程式會選擇不同的斷開時機。

以 Web 為例,瀏覽器向 Web 伺服器傳送請求訊息,Web 伺服器再返回響應訊息,這時收發資料的過程就全部結束了,伺服器一方會發起斷開過程.

當然,可能也有一些程式是客戶端傳送完資料就結束了,不用等伺服器響應,這時客戶端會先發起斷開過程。

這一判斷是應用程式作出的,協議棧在設計上允許任何一方先發起斷開過程。

無論哪種情況,完成資料傳送的一方會發起斷開過程,這裡我們以伺服器一方發起斷開過程為例來進行講解。

伺服器呼叫close程式,TCP頭中的FIN位元設為1

首先,伺服器一方的應用程式會呼叫 Socket 庫的 close 程式。

然後,伺服器的協議棧會生成包含斷開資訊的 TCP 頭部,具體來說就是將控制位中的 FIN 位元設為 1。

伺服器向客戶端傳送資料,伺服器套接字記錄相關資訊

接下來,協議棧會委託 IP 模組向客戶端傳送資料(圖 2.12 ①)。

同時,伺服器的套接字中也會記錄下斷開操作的相關資訊。

客戶端收到資訊後將自己的套接字標記為斷開操作

接下來輪到客戶端了。當收到伺服器發來的 FIN 為 1 的 TCP 頭部時,客戶端的協議棧會將自己的套接字標記為進入斷開操作狀態。

客戶端向伺服器返回ACK號然後呼叫read程式

然後,為了告知伺服器已收到 FIN 為 1 的包,客戶端會向伺服器返回一個 ACK 號(圖 2.12 ②)。這些操作完成後,協議棧就可以等待應用程式來取資料了。

過了一會兒,應用程式就會呼叫 read 來讀取資料。

客戶端協議棧告知應用程式資料接收完畢

這時,協議棧不會嚮應用程式傳遞資料,而是會告知應用程式(瀏覽器)來自伺服器的資料

已經全部收到了。

根據規則,伺服器返回請求之後,Web 通訊操作就全部結束了,因此只要收到伺服器返回的所有資料,客戶端的操作也就隨之結束了。

客戶端呼叫close程式,生成一個TCP包傳送給伺服器

因此,客戶端應用程式會呼叫 close 來結束資料收發操作,這時客戶端的協議棧也會和伺服器一樣,生成一個 FIN 位元為 1 的 TCP 包,然後委託 IP 模組傳送給伺服器(圖 2.12 ③)。

伺服器返回ACK號

一段時間之後,伺服器就會返回ACK 號(圖 2.12 ④)。到這裡,客戶端和伺服器的通訊就全部結束了。

 

2.4.2 刪除套接字

套接字不會被立即刪除防止誤操作

和伺服器的通訊結束之後,用來通訊的套接字也就不會再使用了,這時我們就可以刪除這個套接字了。

不過,套接字並不會立即被刪除,而是會等待一段時間之後再被刪除。

等待這段時間是為了防止誤操作,引發誤操作的原因有很多,這裡無法全部列舉,下面來舉一個最容易理解的例子。

客戶端先發起斷開的操作順序

假設和圖 2.12 的過程相反,客戶端先發起斷開,則斷開的操作順序如下。

(1)客戶端傳送 FIN

(2)伺服器返回 ACK 號

(3)伺服器傳送 FIN

(4)客戶端返回 ACK 號

客戶端傳送的ACK丟失的情況

如果最後客戶端返回的 ACK 號丟失了,這時伺服器沒有接收到 ACK 號,可能會重發一次 FIN。

如果這時客戶端的套接字已經刪除了,那麼套接字中儲存的控制資訊也就跟著消失了,套接字對應的埠號就會被釋放出來。

這時,如果別的應用程式要建立套接字,新套接字碰巧又被分配了同一個埠號,而伺服器重發的 FIN 正好到達。

本來這個 FIN 是要發給剛剛刪除的那個套接字的,但新套接字具有相同的埠號,於是這個 FIN 就會錯誤地跑到新套接字裡面,新套接字就開始執行斷開操作了。

之所以不馬上刪除套接字,就是為了防止這樣的誤操作。至於具體等待多長時間,這和包重傳的操作方式有關。

等待重傳結束後套接字才會被刪除

網路包丟失之後會進行重傳,這個操作通常要持續幾分鐘。

如果重傳了幾分鐘之後依然無效,則停止重傳。

在這段時間內,網路中可能存在重傳的包,也就有可能發生前面講到的這種誤操作,因此需要等待到重傳完全結束。

協議中對於這個等待時間沒有明確的規定,一般來說會等待幾分鐘之後再刪除套接字。

 

2.4.3 資料收發操作小結

到這裡,用 TCP 協議收發應用程式資料的操作就全部結束了。這部分內容的講解比較長,所以最後我們再整理一下。

建立套接字

資料收發操作的第一步是建立套接字。一般來說,伺服器一方的應用程式在啟動時就會建立好套接字並進入等待連線的狀態。

客戶端則一般是在使用者觸發特定動作,需要訪問伺服器的時候建立套接字。

在這個階段,還沒有開始傳輸網路包。建立套接字之後,客戶端會向伺服器發起連線操作。

連線階段

首先,客戶端會生成一個 SYN 為 1 的 TCP 包併發送給伺服器(圖 2.13 ①)。

這個 TCP 包的頭部還包含了客戶端向伺服器傳送資料時使用的初始序號,以及伺服器向客戶端傳送資料時需要用到的視窗大小。

當這個包到達伺服器之後,伺服器會返回一個 SYN 為 1 的 TCP 包(圖 2.13 ②)。

和圖 2.13 ①一樣,這個包的頭部中也包含了序號和視窗大小,此外還包含表示確認已收到包①的

ACK 號。

當這個包到達客戶端時,客戶端會向伺服器返回一個包含表示確認的 ACK 號的 TCP 包(圖 2.13 ③)。

到這裡,連線操作就完成了,雙方進入資料收發階段。

 

資料收發階段

資料收發階段的操作根據應用程式的不同而有一些差異,以 Web 為例,首先客戶端會向伺服器傳送請求訊息。

TCP 會將請求訊息切分成一定大小的塊,並在每一塊前面加上 TCP 頭部,然後傳送給伺服器(圖 2.13 ④)。

TCP 頭部中包含序號,它表示當前傳送的是第幾個位元組的資料。當伺服器收到資料時,會向客戶端返回 ACK 號(圖 2.13 ⑤)。

在最初的階段,伺服器只是不斷接收資料,隨著資料收發的進行,資料不斷傳遞給應用程式,接收緩衝區就會被逐步釋放。

這時,伺服器需要將新的視窗大小告知客戶端。當伺服器收到客戶端的請求訊息後,會向客戶端返回響應訊息,這個過程和剛才的過程正好相反(圖 2.13 ⑥⑦)。

伺服器的響應訊息傳送完畢之後,資料收發操作就結束了,這時就會開始執行斷開操作。

斷開階段

以 Web 為例,伺服器會先發起斷開過程。在這個過程中,伺服器先發送一個 FIN 為 1 的 TCP 包(圖 2.13 ⑧),然後客戶端返回一個表示確認收到的 ACK 號(圖 2.13 ⑨)。

接下來,雙方還會交換一組方向相反的 FIN 為 1 的 TCP 包(圖 2.13 ⑩)和包含 ACK 號的 TCP 包(圖 2.13k)。

最後,在等待一段時間後,套接字會被刪除。