1. 程式人生 > >Linux 網路程式設計 全解(三)--------TCP三次握手、資料傳輸、四次揮手、滑動視窗

Linux 網路程式設計 全解(三)--------TCP三次握手、資料傳輸、四次揮手、滑動視窗

寫在前面:今天中秋佳節,首先祝大家佳節快樂,身體健康,恭喜發財。吃也吃了,喝也喝了,玩也玩了,乾點正事吧。

說一下寫這個系列的目的,隨著對物聯網開發的深入,越來越覺得自己網路基礎知識的薄弱,雖然開發過程中不需要對網路基礎有很深入的瞭解照樣能進行,但有一些問題仍然是不知其因,所以這個系列打算從最基本的網路知識展開記錄,也是一邊學習一邊整理筆記。歡迎大家共同學習,QQ:993650814.  

正文:

一、TCP通訊時序

    先貼一張TCP通訊時序圖,如下:

    

    1、TCP 三次握手

        Linux 網路程式設計 全解(一)--------網路基礎協議

 中已經講了TCP的報文格式,其中報文中的SYN標誌位就表示連線請求的標誌,FIN位表示關閉連線的標誌。上述例子中,是由client端發起連線請求,server端響應請求,最後client發起主動關閉連線的。

    (1)、client傳送段1,帶有連線請求標誌SYN,序號是1000,每發一個數據位元組,這個序號要加 1,這樣在接收端可以根據序號排出資料包的正確順序,也可以發現丟包的情況,另外,規定 SYN 位和 FIN 位也要佔一個序號,這次雖然沒發資料,但是由於發了 SYN 位,因此下次再發送應該用序號 1001。 mss 表示最大段尺寸。

    (2)、伺服器端迴應客戶端, 是三次握手中的第 2 個報文段,同時帶 ACK 標誌和 SYN 標誌。它表示對剛才客戶端SYN 的迴應;伺服器發出段 2,也帶有 SYN 位,同時置 ACK 位表示確認,確認序號是 1001,表示“我成功接收了序號為1001之前的資料,請你下次傳送序號為 1001 的段”,也就是應答了客戶端的連線請求,同時也給客戶端發出一個連線請求,同時宣告最大尺寸為 1024。

    (3)、客戶必須再次迴應伺服器端一個 ACK 報文,這是報文段 3。客戶端發出段 3,對伺服器的連線請求進行應答,確認序號是 8001。在這個過程中,客戶端和伺服器分別給對方發了連線請求,也應答了對方的連線請求,其中伺服器的請求和應答在一個段中發出,因此一共有三個段用於建立連線,稱為“三方握手(three-way-handshake)”。在建立連線的同時,雙方協商 了一些資訊,例如雙方傳送序號的初始值、 最大段尺寸等。

    2、資料傳輸:

    (1)、客戶端發出段 4,包含從序號 1001 開始的 20 個位元組資料。

    (2)、伺服器發出段 5,確認序號為 1021,對序號為 1001-1020 的資料表示確認收到,同時請求傳送序號 1021開始的資料,伺服器在應答的同時也向客戶端傳送從序號 8001 開始的 10 個位元組資料。

    (3)、客戶端發出段 6,對伺服器發來的序號為 8001-8010 的資料表示確認收到,請求傳送序號 8011 開始的資料。

    在資料傳輸過程中, ACK 和確認序號是非常重要的,應用程式交給 TCP 協議傳送的資料會暫存在 TCP 層的傳送緩衝區中,發出資料包給對方之後,只有收到對方應答的 ACK 段才知道該資料包確實發到了對方,可以從傳送緩衝區中釋放掉了,如果因為網路故障丟失了資料包或者丟失了對方發回的 ACK 段,經過等待超時後 TCP 協議自動將傳送緩衝區中的資料包重發。

    3、TCP四次揮手:

    由於 TCP 連線是全雙工的,因此每個方向都必須單獨進行關閉。這原則是當一方完成它的資料傳送任務後就能傳送一個 FIN 來終止這個方向的連線。收到一個 FIN 只意味著這一方向上沒有資料流動。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。

    (1)、客戶端發出段7,FIN位表示關閉連線的請求。

    (2)、伺服器發出段8,應答客戶端發出關閉連線的請求。

    (3)、伺服器發出段9,包含FIN位,向客戶端發出關閉連線的請求。

    (4)、伺服器發出段10,應答伺服器關閉連線的請求。

   半關閉狀態介紹:在TCP四次揮手的過程中可以看出,客戶端發出的段7中包含有FIN標誌位,伺服器端迴應ACK之後並沒有立馬傳送FIN標誌位,此時客戶端處就處在半關閉狀態,此時伺服器可以向客戶端傳送資料,但客戶端只能傳送ACK訊號不能再向伺服器傳送資料了。

    半關閉狀態關閉的不是套接字,而是緩衝區(可參考Linux 網路程式設計 全解(二)--------套接字socket 中的套接字通訊原理圖來檢視原理),所以即使半關閉狀態下,也能傳送ACK訊號,只是不能傳送資料了。

二、滑動視窗(Sliding Window)

    滑動視窗也叫流量控制,在通訊過程中,如果傳送端傳送的速度過快,接收端如果收到資料後處理的速度很慢,而接收緩衝區的大小是固定的,這樣就會丟失資料。TCP通過滑動視窗機制解決這一問題,先看一下原理圖:

                 

    上述通訊過程解析如下:

    1、三次握手:傳送端發起連線,聲明發送的最大資料長度1480Bytes,初始序號是0,視窗大小是4K(表示接我的收緩衝區的還有4K的空閒大小,你傳送的資料不要超過4K)。接收端應答請求連線,宣告最大尺寸1024,初始序號8000,視窗大小6K。

   2、傳送端傳送4~9,每個段帶1K的資料,傳送端根據接收端的視窗知道接收端的緩衝區已經滿了,因此停止傳送。

   3、接收端的應用程式提走2K資料,發出段10,在應答已接收6K的資料同時,宣告視窗大小為2K。 

   4.、接收端的應用程式又提走 2K 資料,接收緩衝區有 4K 空閒,接收端發出段 11,重新宣告視窗大小為 4K。    5、傳送端發出段 12-13,每個段帶 2K 資料,段 13 同時還包含 FIN 位。    6、接收端應答接收到的 2K 資料(6145-8192),再加上 FIN 位佔一個序號 8193,因此應答序號是 8194,連線處於 半關閉狀態,接收端同時宣告視窗大小為 2K。    7、接收端的應用程式提走 2K 資料,接收端重新宣告視窗大小為 4K。    8、接收端的應用程式提走剩下的 2K 資料,接收緩衝區全空,接收端重新宣告視窗大小為 6K。    9、接收端的應用程式在提走全部資料後,決定關閉連線,發出段 17 包含 FIN 位,傳送端應答,連線完全關閉。    上圖在接收端用小方塊表示 1K 資料,實心的小方塊表示已接收到的資料,虛線框表示接收緩衝區,因此套在虛線框中的空心小方塊表示視窗大小,從圖中可以看出,隨著應用程式提走資料,虛線框是向右滑動的,因此稱為滑動視窗。

    從這個例子還可以看出,傳送端是一 K 一 K 地傳送資料,而接收端的應用程式可以兩 K 兩 K 地提走資料,當然也有可能一次提走 3K 或 6K 資料,或者一次只提走幾個位元組的資料。也就是說,應用程式所看到的資料是一個整體,或說是一個流(stream),在底層通訊中這些資料可能被拆成很多資料包來發送,但是一個數據包有多少位元組對應用程式是不可見的,因此 TCP 協議是面向流的協議。而 UDP 是面向訊息的協議,每個 UDP 段都是一條訊息,應用程式必須以訊息為單位提取資料,不能一次提取任意位元組的資料,這一點和 TCP 是很不同的。