日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當前位置:首頁 > > 架構師社區(qū)
[導讀]拿下計網協議后,我就是公園里最靚的仔!

前言

拿下計網協議后,我就是公園里最靚的仔

TCP/IP 基礎知識總結

計算機網絡基礎知識總結

那么下面就開始我們本篇文章,文章組織脈絡如下

40張圖帶你搞懂TCP和UDP

運輸層位于應用層和網絡層之間,是 OSI 分層體系中的第四層,同時也是網絡體系結構的重要部分。運輸層主要負責網絡上的端到端通信。

40張圖帶你搞懂TCP和UDP

運輸層為運行在不同主機上的應用程序之間的通信起著至關重要的作用。下面我們就來一起探討一下關于運輸層的協議部分

運輸層概述

計算機網絡的運輸層非常類似于高速公路,高速公路負責把人或者物品從一端運送到另一端,而計算機網絡的運輸層則負責把報文從一端運輸到另一端,這個端指的就是?端系統(tǒng)。在計算機網絡中,任意一個可以交換信息的介質都可以稱為端系統(tǒng),比如手機、網絡媒體、電腦、運營商等。

在運輸層運輸報文的過程中,會遵守一定的協議規(guī)范,比如一次傳輸的數據限制、選擇什么樣的運輸協議等。運輸層實現了讓兩個互不相關的主機進行邏輯通信的功能,看起來像是讓兩個主機相連一樣。

運輸層協議是在端系統(tǒng)中實現的,而不是在路由器中實現的。路由只是做識別地址并轉發(fā)的功能。這就比如快遞員送快遞一樣,當然是要由地址的接受人也就是 xxx 號樓 xxx 單元 xxx 室的這個人來判斷了!

40張圖帶你搞懂TCP和UDP

TCP 如何判斷是哪個端口的呢?

還記得數據包的結構嗎,這里來回顧一下

40張圖帶你搞懂TCP和UDP

數據包經過每層后,該層協議都會在數據包附上包首部,一個完整的包首部圖如上所示。

在數據傳輸到運輸層后,會為其附上 TCP 首部,首部包含著源端口號和目的端口號。

在發(fā)送端,運輸層將從發(fā)送應用程序進程接收到的報文轉化成運輸層分組,分組在計算機網絡中也稱為?報文段(segment)。運輸層一般會將報文段進行分割,分割成為較小的塊,為每一塊加上運輸層首部并將其向目的地發(fā)送。

在發(fā)送過程中,可選的運輸層協議(也就是交通工具) 主要有?TCP?和?UDP?,關于這兩種運輸協議的選擇及其特性也是我們著重探討的重點。

TCP 和 UDP 前置知識

在 TCP/IP 協議中能夠實現傳輸層功能的,最具代表性的就是 TCP 和 UDP。提起 TCP 和 UDP ,就得先從這兩個協議的定義說起。

TCP 叫做傳輸控制協議(TCP,Transmission Control Protocol),通過名稱可以大致知道 TCP 協議有控制傳輸的功能,主要體現在其可控,可控就表示著可靠,確實是這樣的,TCP 為應用層提供了一種可靠的、面向連接的服務,它能夠將分組可靠的傳輸到服務端。

UDP 叫做?用戶數據報協議(UDP,User Datagram Protocol),通過名稱可以知道 UDP 把重點放在了數據報上,它為應用層提供了一種無需建立連接就可以直接發(fā)送數據報的方法。

怎么計算機網絡中的術語對一個數據的描述這么多啊?

在計算機網絡中,在不同層之間會有不同的描述。我們上面提到會將運輸層的分組稱為報文段,除此之外,還會將 TCP 中的分組也稱為報文段,然而將 UDP 的分組稱為數據報,同時也將網絡層的分組稱為數據報

40張圖帶你搞懂TCP和UDP

但是為了統(tǒng)一,一般在計算機網絡中我們統(tǒng)一稱 TCP 和 UDP 的報文為?報文段,這個就相當于是約定,到底如何稱呼不用過多糾結啦。

套接字

在 TCP 或者 UDP 發(fā)送具體的報文信息前,需要先經過一扇?,這個門就是套接字(socket),套接字向上連接著應用層,向下連接著網絡層。在操作系統(tǒng)中,操作系統(tǒng)分別為應用和硬件提供了接口(Application Programming Interface)。而在計算機網絡中,套接字同樣是一種接口,它也是有接口 API 的。

使用 TCP 或 UDP 通信時,會廣泛用到套接字的 API,使用這套 API 設置 IP 地址、端口號,實現數據的發(fā)送和接收。

40張圖帶你搞懂TCP和UDP

現在我們知道了, Socket 和 TCP/IP 沒有必然聯系,Socket 的出現只是方便了 TCP/IP 的使用,如何方便使用呢?你可以直接使用下面 Socket API 的這些方法。

40張圖帶你搞懂TCP和UDP

套接字類型

套接字的主要類型有三種,下面我們分別介紹一下

  • 數據報套接字(Datagram sockets):數據報套接字提供一種無連接的服務,而且并不能保證數據傳輸的可靠性。數據有可能在傳輸過程中丟失或出現數據重復,且無法保證順序地接收到數據。數據報套接字使用UDP( User DatagramProtocol)協議進行數據的傳輸。由于數據報套接字不能保證數據傳輸的可靠性,對于有可能出現的數據丟失情況,需要在程序中做相應的處理。

  • 流套接字(Stream sockets):流套接字用于提供面向連接、可靠的數據傳輸服務。能夠保證數據的可靠性、順序性。流套接字之所以能夠實現可靠的數據服務,原因在于其使用了傳輸控制協議,即?TCP(The Transmission Control Protocol)協議

  • 原始套接字(Raw sockets): 原始套接字允許直接發(fā)送和接收 IP 數據包,而無需任何特定于協議的傳輸層格式,原始套接字可以讀寫內核沒有處理過的 IP 數據包。

套接字處理過程

在計算機網絡中,要想實現通信,必須至少需要兩個端系統(tǒng),至少需要一對兩個套接字才行。下面是套接字的通信過程。

40張圖帶你搞懂TCP和UDP

  1. socket 中的 API 用于創(chuàng)建通信鏈路中的端點,創(chuàng)建完成后,會返回描述該套接字的套接字描述符。

就像使用文件描述符來訪問文件一樣,套接字描述符用來訪問套接字。

  1. 當應用程序具有套接字描述符后,它可以將唯一的名稱綁定在套接字上,服務器必須綁定一個名稱才能在網絡中訪問

  2. 在為服務端分配了 socket 并且將名稱使用 bind 綁定到套接字上后,將會調用 listen api。listen?表示客戶端愿意等待連接的意愿,listen 必須在 accept api 之前調用。

  3. 客戶端應用程序在流套接字(基于 TCP)上調用?connect?發(fā)起與服務器的連接請求。

  4. 服務器應用程序使用acceptAPI 接受客戶端連接請求,服務器必須先成功調用 bind 和 listen 后,再調用 accept api。

  5. 在流套接字之間建立連接后,客戶端和服務器就可以發(fā)起 read/write api 調用了。

  6. 當服務器或客戶端要停止操作時,就會調用?close?API 釋放套接字獲取的所有系統(tǒng)資源。

雖然套接字 API 位于應用程序層和傳輸層之間的通信模型中,但是套接字 API 不屬于通信模型。套接字 API 允許應用程序與傳輸層和網絡層進行交互。

在往下繼續(xù)聊之前,我們先播放一個小插曲,簡單聊一聊 IP。

聊聊 IP

IP?是Internet Protocol(網際互連協議)的縮寫,是 TCP/IP 體系中的網絡層協議。設計 IP 的初衷主要想解決兩類問題

  • 提高網絡擴展性:實現大規(guī)模網絡互聯

  • 對應用層和鏈路層進行解藕,讓二者獨立發(fā)展。

IP 是整個 TCP/IP 協議族的核心,也是構成互聯網的基礎。為了實現大規(guī)模網絡的互通互聯,IP 更加注重適應性、簡潔性和可操作性,并在可靠性做了一定的犧牲。IP 不保證分組的交付時限和可靠性,所傳送分組有可能出現丟失、重復、延遲或亂序等問題。

我們知道,TCP 協議的下一層就是 IP 協議層,既然 IP 不可靠,那么如何保證數據能夠準確無誤地到達呢?

這就涉及到 TCP 傳輸機制的問題了,我們后面聊到 TCP 的時候再說。

端口號

在聊端口號前,先來聊一聊文件描述以及 socket 和端口號的關系

為了方便資源的使用,提高機器的性能、利用率和穩(wěn)定性等等原因,我們的計算機都有一層軟件叫做操作系統(tǒng),它用于幫我們管理計算機可以使用的資源,當我們的程序要使用一個資源的時候,可以向操作系統(tǒng)申請,再由操作系統(tǒng)為我們的程序分配和管理資源。通常當我們要訪問一個內核設備或文件時,程序可以調用系統(tǒng)函數,系統(tǒng)就會為我們打開設備或文件,然后返回一個文件描述符fd(或稱為ID,是一個整數),我們要訪問該設備或文件,只能通過該文件描述符??梢哉J為該編號對應著打開的文件或設備。

而當我們的程序要使用網絡時,要使用到對應的操作系統(tǒng)內核的操作和網卡設備,所以我們可以向操作系統(tǒng)申請,然后系統(tǒng)會為我們創(chuàng)建一個套接字 Socket,并返回這個 Socket 的ID,以后我們的程序要使用網絡資源,只要向這個 Socket 的編號 ID 操作即可。而我們的每一個網絡通信的進程至少對應著一個 Socket。向 Socket 的 ID 中寫數據,相當于向網絡發(fā)送數據,向 Socket 中讀數據,相當于接收數據。而且這些套接字都有唯一標識符——文件描述符 fd。

端口號是?16?位的非負整數,它的范圍是 0 - 65535 之間,這個范圍會分為三種不同的端口號段,由 Internet 號碼分配機構 IANA 進行分配

  • 周知/標準端口號,它的范圍是 0 - 1023

  • 注冊端口號,范圍是 1024 - 49151

  • 私有端口號,范圍是 49152 - 6553

一臺計算機上可以運行多個應用程序,當一個報文段到達主機后,應該傳輸給哪個應用程序呢?你怎么知道這個報文段就是傳遞給 HTTP 服務器而不是 SSH 服務器的呢?

是憑借端口號嗎?當報文到達服務器時,是端口號來區(qū)分不同應用程序的,所以應該借助端口號來區(qū)分。

舉個例子反駁一下 cxuan,假如到達服務器的兩條數據都是由 80 端口發(fā)出的你該如何區(qū)分呢?或者說到達服務器的兩條數據端口一樣,協議不同,該如何區(qū)分呢?

所以僅憑端口號來確定某一條報文顯然是不夠的。

互聯網上一般使用?源 IP 地址、目標 IP 地址、源端口號、目標端口號?來進行區(qū)分。如果其中的某一項不同,就被認為是不同的報文段。這些也是多路分解和多路復用?的基礎。

確定端口號

在實際通信之前,需要先確定一下端口號,確定端口號的方法分為兩種:

  • 標準既定的端口號

標準既定的端口號是靜態(tài)分配的,每個程序都會有自己的端口號,每個端口號都有不同的用途。端口號是一個 16 比特的數,其大小在 0 - 65535 之間,0 - 1023 范圍內的端口號都是動態(tài)分配的既定端口號,例如 HTTP 使用 80 端口來標識,FTP 使用 21 端口來標識,SSH 使用 22 來標識。這類端口號有一個特殊的名字,叫做?周知端口號(Well-Known Port Number)。

  • 時序分配的端口號

第二種分配端口號的方式是一種動態(tài)分配法,在這種方法下,客戶端應用程序可以完全不用自己設置端口號,憑借操作系統(tǒng)進行分配,操作系統(tǒng)可以為每個應用程序分配互不沖突的端口號。這種動態(tài)分配端口號的機制即使是同一個客戶端發(fā)起的 TCP 連接,也能識別不同的連接。

多路復用和多路分解

我們上面聊到了在主機上的每個套接字都會分配一個端口號,當報文段到達主機時,運輸層會檢查報文段中的目的端口號,并將其定向到相應的套接字,然后報文段中的數據通過套接字進入其所連接的進程。下面我們來聊一下什么是多路復用和多路分解的概念。

多路復用和多路分解分為兩種,即無連接的多路復用(多路分解)和面向連接的多路復用(多路分解)

無連接的多路復用和多路分解

開發(fā)人員會編寫代碼確定端口號是周知端口號還是時序分配的端口號。假如主機 A 中的一個 10637 端口要向主機 B 中的 45438 端口發(fā)送數據,運輸層采用的是?UDP?協議,數據在應用層產生后,會在運輸層中加工處理,然后在網絡層將數據封裝得到 IP 數據報,IP 數據包通過鏈路層盡力而為的交付給主機 B,然后主機 B 會檢查報文段中的端口號判斷是哪個套接字的,這一系列的過程如下所示

40張圖帶你搞懂TCP和UDP

UDP 套接字就是一個二元組,二元組包含目的 IP 地址和目的端口號。

所以,如果兩個 UDP 報文段有不同的源 IP 地址和/或相同的源端口號,但是具有相同的目的 IP 地址和目的端口號,那么這兩個報文會通過套接字定位到相同的目的進程。

這里思考一個問題,主機 A 給主機 B 發(fā)送一個消息,為什么還需要知道源端口號呢?比如我給妹子表達出我對你有點意思的信息,妹子還需要知道這個信息是從我的哪個器官發(fā)出的嗎?知道是我這個人對你有點意思不就完了?實際上是需要的,因為妹子如果要表達出她對你也有點意思,她是不是可能會親你一口,那她得知道往哪親吧?

這就是,在 A 到 B 的報文段中,源端口號會作為?返回地址?的一部分,即當 B 需要回發(fā)一個報文段給 A 時,B 需要從 A 到 B 中的源端口號取值,如下圖所示

40張圖帶你搞懂TCP和UDP

面向連接的多路復用與多路分解

如果說無連接的多路復用和多路分解指的是 UDP 的話,那么面向連接的多路復用與多路分解指的是 TCP 了,TCP 和 UDP 在報文結構上的差別是,UDP 是一個二元組而 TCP 是一個四元組,即源 IP 地址、目標 IP 地址、源端口號、目標端口號?,這個我們上面也提到了。當一個 TCP 報文段從網絡到達一臺主機時,這個主機會根據這四個值拆解到對應的套接字上。

40張圖帶你搞懂TCP和UDP

上圖顯示了面向連接的多路復用和多路分解的過程,圖中主機 C 向主機 B 發(fā)起了兩個 HTTP 請求,主機 A 向主機 C 發(fā)起了一個 HTTP 請求,主機 A、B、C 都有自己唯一的 IP 地址,當主機 C 發(fā)出 HTTP 請求后,主機 B 能夠分解這兩個 HTTP 連接,因為主機 C 發(fā)出請求的兩個源端口號不同,所以對于主機 B 來說,這是兩條請求,主機 B 能夠進行分解。對于主機 A 和主機 C 來說,這兩個主機有不同的 IP 地址,所以對于主機 B 來說,也能夠進行分解。

UDP

終于,我們開始了對 UDP 協議的探討,淦起!

UDP 的全稱是?用戶數據報協議(UDP,User Datagram Protocol),UDP 為應用程序提供了一種無需建立連接就可以發(fā)送封裝的 IP 數據包的方法。如果應用程序開發(fā)人員選擇的是 UDP 而不是 TCP 的話,那么該應用程序相當于就是和 IP 直接打交道的。

從應用程序傳遞過來的數據,會附加上多路復用/多路分解的源和目的端口號字段,以及其他字段,然后將形成的報文傳遞給網絡層,網絡層將運輸層報文段封裝到 IP 數據報中,然后盡力而為的交付給目標主機。最關鍵的一點就是,使用 UDP 協議在將數據報傳遞給目標主機時,發(fā)送方和接收方的運輸層實體間是沒有握手的。正因為如此,UDP 被稱為是無連接的協議。

UDP 特點

UDP 協議一般作為流媒體應用、語音交流、視頻會議所使用的傳輸層協議,我們大家都知道的 DNS 協議底層也使用了 UDP 協議,這些應用或協議之所以選擇 UDP 主要是因為以下這幾點

  • 速度快,采用 UDP 協議時,只要應用進程將數據傳給 UDP,UDP 就會將此數據打包進 UDP 報文段并立刻傳遞給網絡層,然后 TCP 有擁塞控制的功能,它會在發(fā)送前判斷互聯網的擁堵情況,如果互聯網極度阻塞,那么就會抑制 TCP 的發(fā)送方。使用 UDP 的目的就是希望實時性。

  • 無須建立連接,TCP 在數據傳輸之前需要經過三次握手的操作,而 UDP 則無須任何準備即可進行數據傳輸。因此 UDP 沒有建立連接的時延。如果使用 TCP 和 UDP 來比喻開發(fā)人員:TCP 就是那種凡事都要設計好,沒設計不會進行開發(fā)的工程師,需要把一切因素考慮在內后再開干!所以非常靠譜;而 UDP 就是那種上來直接干干干,接到項目需求馬上就開干,也不管設計,也不管技術選型,就是干,這種開發(fā)人員非常不靠譜,但是適合快速迭代開發(fā),因為可以馬上上手!

  • 無連接狀態(tài),TCP 需要在端系統(tǒng)中維護連接狀態(tài),連接狀態(tài)包括接收和發(fā)送緩存、擁塞控制參數以及序號和確認號的參數,在 UDP 中沒有這些參數,也沒有發(fā)送緩存和接受緩存。因此,某些專門用于某種特定應用的服務器當應用程序運行在 UDP 上,一般能支持更多的活躍用戶

  • 分組首部開銷小,每個 TCP 報文段都有 20 字節(jié)的首部開銷,而 UDP 僅僅只有 8 字節(jié)的開銷。

這里需要注意一點,并不是所有使用 UDP 協議的應用層都是不可靠的,應用程序可以自己實現可靠的數據傳輸,通過增加確認和重傳機制。所以使用 UDP 協議最大的特點就是速度快。

UDP 報文結構

下面來一起看一下 UDP 的報文結構,每個 UDP 報文分為 UDP 報頭和 UDP 數據區(qū)兩部分。報頭由 4 個 16 位長(2 字節(jié))字段組成,分別說明該報文的源端口、目的端口、報文長度和校驗值。

40張圖帶你搞懂TCP和UDP

  • 源端口號(Source Port)?:這個字段占據 UDP 報文頭的前 16 位,通常包含發(fā)送數據報的應用程序所使用的 UDP 端口。接收端的應用程序利用這個字段的值作為發(fā)送響應的目的地址。這個字段是可選項,有時不會設置源端口號。沒有源端口號就默認為 0 ,通常用于不需要返回消息的通信中。

  • 目標端口號(Destination Port): 表示接收端端口,字段長為 16 位

  • 長度(Length): 該字段占據 16 位,表示 UDP 數據報長度,包含 UDP 報文頭和 UDP 數據長度。因為 UDP 報文頭長度是 8 個字節(jié),所以這個值最小為 8,最大長度為 65535 字節(jié)。

  • 校驗和(Checksum):UDP 使用校驗和來保證數據安全性,UDP 的校驗和也提供了差錯檢測功能,差錯檢測用于校驗報文段從源到目標主機的過程中,數據的完整性是否發(fā)生了改變。發(fā)送方的 UDP 對報文段中的 16 比特字的和進行反碼運算,求和時遇到的位溢出都會被忽略,比如下面這個例子,三個 16 比特的數字進行相加

40張圖帶你搞懂TCP和UDP

這些 16 比特的前兩個和是

40張圖帶你搞懂TCP和UDP

然后再將上面的結果和第三個 16 比特的數進行相加

40張圖帶你搞懂TCP和UDP

最后一次相加的位會進行溢出,溢出位 1 要被舍棄,然后進行反碼運算,反碼運算就是將所有的 1 變?yōu)?0 ,0 變?yōu)?1。因此?1000 0100 1001 0101?的反碼就是?0111 1011 0110 1010,這就是校驗和,如果在接收方,數據沒有出現差錯,那么全部的 4 個 16 比特的數值進行運算,同時也包括校驗和,如果最后結果的值不是 1111 1111 1111 1111 的話,那么就表示傳輸過程中的數據出現了差錯。

下面來想一個問題,為什么 UDP 會提供差錯檢測的功能?

這其實是一種?端到端?的設計原則,這個原則說的是要讓傳輸中各種錯誤發(fā)生的概率降低到一個可以接受的水平。

文件從主機A傳到主機B,也就是說AB主機要通信,需要經過三個環(huán)節(jié):首先是主機A從磁盤上讀取文件并將數據分組成一個個數據包packet,,然后數據包通過連接主機A和主機B的網絡傳輸到主機B,最后是主機B收到數據包并將數據包寫入磁盤。在這個看似簡單其實很復雜的過程中可能會由于某些原因而影響正常通信。比如:磁盤上文件讀寫錯誤、緩沖溢出、內存出錯、網絡擁擠等等這些因素都有可能導致數據包的出錯或者丟失,由此可見用于通信的網絡是不可靠的。

由于實現通信只要經過上述三個環(huán)節(jié),那么我們就想是否在其中某個環(huán)節(jié)上增加一個檢錯糾錯機制來用于對信息進行把關呢?

網絡層肯定不能做這件事,因為網絡層的最主要目的是增大數據傳輸的速率,網絡層不需要考慮數據的完整性,數據的完整性和正確性交給端系統(tǒng)去檢測就行了,因此在數據傳輸中,對于網絡層只能要求其提供盡可能好的數據傳輸服務,而不可能寄希望于網絡層提供數據完整性的服務。

UDP 不可靠的原因是它雖然提供差錯檢測的功能,但是對于差錯沒有恢復能力更不會有重傳機制。

TCP

UDP 是一種沒有復雜的控制,提供無連接通信服務的一種協議,換句話說,它將部分控制部分交給應用程序去處理,自己只提供作為傳輸層協議最基本的功能。

而與 UDP 不同的是,同樣作為傳輸層協議,TCP 協議要比 UDP 的功能多很多。

TCP?的全稱是?Transmission Control Protocol,它被稱為是一種面向連接(connection-oriented)?的協議,這是因為一個應用程序開始向另一個應用程序發(fā)送數據之前,這兩個進程必須先進行握手,握手是一個邏輯連接,并不是兩個主機之間進行真實的握手。

40張圖帶你搞懂TCP和UDP

這個連接是指各種設備、線路或者網絡中進行通信的兩個應用程序為了相互傳遞消息而專有的、虛擬的通信鏈路,也叫做虛擬電路。

一旦主機 A 和主機 B 建立了連接,那么進行通信的應用程序只使用這個虛擬的通信線路發(fā)送和接收數據就可以保證數據的傳輸,TCP 協議負責控制連接的建立、斷開、保持等工作。

TCP 連接是全雙工服務(full-duplex service)?的,全雙工是什么意思?全雙工指的是主機 A 與另外一個主機 B 存在一條 TCP 連接,那么應用程數據就可以從主機 B 流向主機 A 的同時,也從主機 A 流向主機 B。

TCP 只能進行?點對點(point-to-point)?連接,那么所謂的多播,即一個主機對多個接收方發(fā)送消息的情況是不存在的,TCP 連接只能連接兩個一對主機。

40張圖帶你搞懂TCP和UDP

TCP 的連接建立需要經過三次握手,這個我們下面再說。一旦 TCP 連接建立后,主機之間就可以相互發(fā)送數據了,客戶進程通過套接字傳送數據流。數據一旦通過套接字后,它就由客戶中運行的 TCP 協議所控制。

TCP 會將數據臨時存儲到連接的發(fā)送緩存(send buffer)?中,這個 send buffer 是三次握手之間設置的緩存之一,然后 TCP 在合適的時間將發(fā)送緩存中的數據發(fā)送到目標主機的接收緩存中,實際上,每一端都會有發(fā)送緩存和接收緩存,如下所示

40張圖帶你搞懂TCP和UDP

主機之間的發(fā)送是以?報文段(segment)?進行的,那么什么是 Segement 呢?

TCP 會將要傳輸的數據流分為多個塊(chunk),然后向每個 chunk 中添加 TCP 標頭,這樣就形成了一個 TCP 段也就是報文段。每一個報文段可以傳輸的長度是有限的,不能超過最大數據長度(Maximum Segment Size),俗稱?MSS。在報文段向下傳輸的過程中,會經過鏈路層,鏈路層有一個?Maximum Transmission Unit?,最大傳輸單元 MTU, 即數據鏈路層上所能通過最大數據包的大小,最大傳輸單元通常與通信接口有關。

那么 MSS 和 MTU 有啥關系呢?

因為計算機網絡是分層考慮的,這個很重要,不同層的稱呼不一樣,對于傳輸層來說,稱為報文段而對網絡層來說就叫做 IP 數據包,所以,MTU 可以認為是網絡層能夠傳輸的最大 IP 數據包,而 MSS(Maximum segment size)可以認為是傳輸層的概念,也就是 TCP 數據包每次能夠傳輸的最大量。

TCP 報文段結構

在簡單聊了聊 TCP 連接后,下面我們就來聊一下 TCP 的報文段結構,如下圖所示

40張圖帶你搞懂TCP和UDP

TCP 報文段結構相比 UDP 報文結構多了很多內容。但是前兩個 32 比特的字段是一樣的。它們是?源端口號?和?目標端口號,我們知道,這兩個字段是用于多路復用和多路分解的。另外,和 UDP 一樣,TCP 也包含校驗和(checksum field)?,除此之外,TCP 報文段首部還有下面這些

  • 32 比特的序號字段(sequence number field)?和 32 比特的確認號字段(acknowledgment number field)?。這些字段被 TCP 發(fā)送方和接收方用來實現可靠的數據傳輸。

  • 4 比特的首部字段長度字段(header length field),這個字段指示了以 32 比特的字為單位的 TCP 首部長度。TCP 首部的長度是可變的,但是通常情況下,選項字段為空,所以 TCP 首部字段的長度是 20 字節(jié)。

  • 16 比特的?接受窗口字段(receive window field)?,這個字段用于流量控制。它用于指示接收方能夠/愿意接受的字節(jié)數量

  • 可變的選項字段(options field),這個字段用于發(fā)送方和接收方協商最大報文長度,也就是 MSS 時使用

  • 6 比特的?標志字段(flag field),?ACK?標志用于指示確認字段中的值是有效的,這個報文段包括一個對已被成功接收報文段的確認;RST、SYN、FIN?標志用于連接的建立和關閉;CWR?和?ECE?用于擁塞控制;PSH?標志用于表示立刻將數據交給上層處理;URG?標志用來表示數據中存在需要被上層處理的?緊急?數據。緊急數據最后一個字節(jié)由 16 比特的緊急數據指針字段(urgeent data pointer field)?指出。一般情況下,PSH 和 URG 并沒有使用。

TCP 的各種功能和特點都是通過 TCP 報文結構來體現的,在聊完 TCP 報文結構之后,我們下面就來聊一下 TCP 有哪些功能及其特點了。

序號、確認號實現傳輸可靠性

TCP 報文段首部中兩個最重要的字段就是?序號?和?確認號,這兩個字段是 TCP 實現可靠性的基礎,那么你肯定好奇如何實現可靠性呢?要了解這一點,首先我們得先知道這兩個字段里面存了哪些內容吧?

一個報文段的序號就是數據流的字節(jié)編號?。因為 TCP 會把數據流分割成為一段一段的字節(jié)流,因為字節(jié)流本身是有序的,所以每一段的字節(jié)編號就是標示是哪一段的字節(jié)流。比如,主機 A 要給主機 B 發(fā)送一條數據。數據經過應用層產生后會有一串數據流,數據流會經過 TCP 分割,分割的依據就是 MSS,假設數據是 10000 字節(jié),MSS 是 2000 字節(jié),那么 TCP 就會把數據拆分成 0 - 1999 , 2000 - 3999 的段,依次類推。

所以,第一個數據 0 - 1999 的首字節(jié)編號就是 0 ,2000 - 3999 的首字節(jié)編號就是 2000 。

然后,每個序號都會被填入 TCP 報文段首部的序號字段中。

40張圖帶你搞懂TCP和UDP

至于確認號的話,會比序號要稍微麻煩一些。這里我們先拓展下幾種通信模型。

  • 單工通信:單工數據傳輸只支持數據在一個方向上傳輸;在同一時間只有一方能接受或發(fā)送信息,不能實現雙向通信,比如廣播、電視等。

  • 雙工通信是一種點對點系統(tǒng),由兩個或者多個在兩個方向上相互通信的連接方或者設備組成。雙工通信模型有兩種:全雙工(FDX)和半雙工(HDX)

  • 全雙工:在全雙工系統(tǒng)中,連接雙方可以相互通信,一個最常見的例子就是電話通信。全雙工通信是兩個單工通信方式的結合,它要求發(fā)送設備和接收設備都有獨立的接收和發(fā)送能力。

  • 半雙工:在半雙工系統(tǒng)中,連接雙方可以彼此通信,但不能同時通信,比如對講機,只有把按鈕按住的人才能夠講話,只有一個人講完話后另外一個人才能講話。

單工、半雙工、全雙工通信如下圖所示

40張圖帶你搞懂TCP和UDP

TCP 是一種全雙工的通信協議,因此主機 A 在向主機 B 發(fā)送消息的過程中,也在接受來自主機 B 的數據。主機 A 填充進報文段的確認號是期望從主機 B 收到的下一字節(jié)的序號。稍微有點繞,我們來舉個例子看一下。比如主機 A 收到了來自主機 B 發(fā)送的編號為 0 - 999 字節(jié)的報文段,這個報文段會寫入序號中,隨后主機 A 期望能夠從主機 B 收到 1000 - 剩下的報文段,因此,主機 A 發(fā)送到主機 B 的報文段中,它的確認號就是 1000 。

累積確認

這里再舉出一個例子,比如主機 A 在發(fā)送 0 - 999 報文段后,期望能夠接受到 1000 之后的報文段,但是主機 B 卻給主機 A 發(fā)送了一個 1500 之后的報文段,那么主機 A 是否還會繼續(xù)進行等待呢?

答案顯然是會的,因為 TCP 只會確認流中至第一個丟失字節(jié)為止的字節(jié),因為 1500 雖然屬于 1000 之后的字節(jié),但是主機 B 沒有給主機 A 發(fā)送 1000 - 1499 之間的字節(jié),所以主機 A 會繼續(xù)等待。

在了解完序號和確認號之后,我們下面來聊一下 TCP 的發(fā)送過程。下面是一個正常的發(fā)送過程

40張圖帶你搞懂TCP和UDP

TCP 通過肯定的確認應答(ACK)?來實現可靠的數據傳輸,當主機 A將數據發(fā)出之后會等待主機 B 的響應。如果有確認應答(ACK),說明數據已經成功到達對端。反之,則數據很可能會丟失。

如下圖所示,如果在一定時間內主機 A 沒有等到確認應答,則認為主機 B 發(fā)送的報文段已經丟失,并進行重發(fā)。

40張圖帶你搞懂TCP和UDP

主機 A 給主機 B 的響應可能由于網絡抖動等原因無法到達,那么在經過特定的時間間隔后,主機 A 將重新發(fā)送報文段。

主機 A 沒有收到主機 B 的響應還可能是因為主機 B 在發(fā)送給主機 A 的過程中丟失。

40張圖帶你搞懂TCP和UDP

如上圖所示,由主機 B 返回的確認應答,由于網絡擁堵等原因在傳送的過程中丟失,并沒有到達主機 A。主機 A 會等待一段時間,如果在這段時間內主機 A 仍沒有等到主機 B 的響應,那么主機 A 會重新發(fā)送報文段。

那么現在就存在一個問題,如果主機 A 給主機 B 發(fā)送了一個報文段后,主機 B 接受到報文段發(fā)送響應,此刻由于網絡原因,這個報文段并未到達,等到一段時間后主機 A 重新發(fā)送報文段,然后此時主機 B 發(fā)送的響應在主機 A 第二次發(fā)送后失序到達主機 A,那么主機 A 應該如何處理呢?

40張圖帶你搞懂TCP和UDP

TCP RFC 并未為此做任何規(guī)定,也就是說,我們可以自己決定如何處理失序到達的報文段。一般處理方式有兩種

  • 接收方立刻丟棄失序的報文段

  • 接收方接受失序到達的報文段,并等待后續(xù)的報文段

一般來說通常采取的做法是第二種。

傳輸控制

利用窗口控制提高速度

前面我們介紹了 TCP 是以數據段的形式進行發(fā)送,如果經過一段時間內主機 A 等不到主機 B 的響應,主機 A 就會重新發(fā)送報文段,接受到主機 B 的響應,再會繼續(xù)發(fā)送后面的報文段,我們現在看到,這一問一答的形式還存在許多條件,比如響應未收到、等待響應等,那么對崇尚性能的互聯網來說,這種形式的性能應該不會很高。

40張圖帶你搞懂TCP和UDP

那么如何提升性能呢?

為了解決這個問題,TCP 引入了?窗口?這個概念,即使在往返時間較長、頻次很多的情況下,它也能控制網絡性能的下降,聽起來很牛批,那它是如何實現的呢?

如下圖所示

40張圖帶你搞懂TCP和UDP

我們之前每次請求發(fā)送都是以報文段的形式進行的,引入窗口后,每次請求都可以發(fā)送多個報文段,也就是說一個窗口可以發(fā)送多個報文段。窗口大小就是指無需等待確認應答就可以繼續(xù)發(fā)送報文段的最大值。

在這個窗口機制中,大量使用了?緩沖區(qū)?,通過對多個段同時進行確認應答的功能。

如下圖所示,發(fā)送報文段中高亮部分即是我們提到的窗口,在窗口內,即使沒有收到確認應答也可以把請求發(fā)送出去。不過,在整個窗口的確認應答沒有到達之前,如果部分報文段丟失,那么主機 A 將仍會重傳。為此,主機 A 需要設置緩存來保留這些需要重傳的報文段,直到收到他們的確認應答。

40張圖帶你搞懂TCP和UDP

在滑動窗口以外的部分是尚未發(fā)送的報文段和已經接受到的報文段,如果報文段已經收到確認則不可進行重發(fā),此時報文段就可以從緩沖區(qū)中清除。

在收到確認的情況下,會將窗口滑動到確認應答中確認號的位置,如上圖所示,這樣可以順序的將多個段同時發(fā)送,用以提高通信性能,這種窗口也叫做?滑動窗口(Sliding window)。

窗口控制和重發(fā)

報文段的發(fā)送和接收,必然伴隨著報文段的丟失和重發(fā),窗口也是同樣如此,如果在窗口中報文段發(fā)送過程中出現丟失怎么辦?

首先我們先考慮確認應答沒有返回的情況。在這種情況下,主機 A 發(fā)送的報文段到達主機 B,是不需要再進行重發(fā)的。這和單個報文段的發(fā)送不一樣,如果發(fā)送單個報文段,即使確認應答沒有返回,也要進行重發(fā)

40張圖帶你搞懂TCP和UDP

窗口在一定程度上比較大時,即使有少部分確認應答的丟失,也不會重新發(fā)送報文段。

我們知道,如果在某個情況下由于發(fā)送的報文段丟失,導致接受主機未收到請求,或者主機返回的響應未到達客戶端的話,會經過一段時間重傳報文。那么在使用窗口的情況下,報文段丟失會怎么樣呢?

如下圖所示,報文段 0 - 999 丟失后,但是主機 A 并不會等待,主機 A 會繼續(xù)發(fā)送余下的報文段,主機 B 發(fā)送的確認應答卻一直是 1000,同一個確認號的應答報文會被持續(xù)不斷的返回,如果發(fā)送端主機在連續(xù) 3 次收到同一個確認應答后,就會將其所對應的數據重發(fā),這種機制要比之前提到的超時重發(fā)更加高效,這種機制也被稱為?高速重發(fā)控制。這種重發(fā)的確認應答也被稱為?冗余 ACK(響應)。

40張圖帶你搞懂TCP和UDP

主機 B 在沒有接收到自己期望序列號的報文段時,會對之前收到的數據進行確認應答。發(fā)送端則一旦收到某個確認應答后,又連續(xù)三次收到同樣的確認應答,那么就會認為報文段已經丟失。需要進行重發(fā)。使用這種機制可以提供更為快速的重發(fā)服務。

流量控制

前面聊的是傳輸控制,下面 cxuan 再和你聊一下?流量控制。我們知道,在每個 TCP 連接的一側主機都會有一個 socket 緩沖區(qū),緩沖區(qū)會為每個連接設置接收緩存和發(fā)送緩存,當 TCP 建立連接后,從應用程序產生的數據就會到達接收方的接收緩沖區(qū)中,接收方的應用程序并不一定會馬上讀取緩沖區(qū)的數據,它需要等待操作系統(tǒng)分配時間片。如果此時發(fā)送方的應用程序產生數據過快,而接收方讀取接受緩沖區(qū)的數據相對較慢的話,那么接收方中緩沖區(qū)的數據將會溢出。

但是還好,TCP 有?流量控制服務(flow-control service)?用于消除緩沖區(qū)溢出的情況。流量控制是一個速度匹配服務,即發(fā)送方的發(fā)送速率與接受方應用程序的讀取速率相匹配。

TCP 通過使用一個?接收窗口(receive window)?的變量來提供流量控制。接受窗口會給發(fā)送方一個指示到底還有多少可用的緩存空間。發(fā)送端會根據接收端的實際接受能力來控制發(fā)送的數據量。

接收端主機向發(fā)送端主機通知自己可以接收數據的大小,發(fā)送端會發(fā)送不超過這個限度的數據,這個大小限度就是窗口大小,還記得 TCP 的首部么,有一個接收窗口,我們上面聊的時候說這個字段用于流量控制。它用于指示接收方能夠/愿意接受的字節(jié)數量。

那么只知道這個字段用于流量控制,那么如何控制呢?

發(fā)送端主機會定期發(fā)送一個窗口探測包,這個包用于探測接收端主機是否還能夠接受數據,當接收端的緩沖區(qū)一旦面臨數據溢出的風險時,窗口大小的值也隨之被設置為一個更小的值通知發(fā)送端,從而控制數據發(fā)送量。

下面是一個流量控制示意圖

40張圖帶你搞懂TCP和UDP

發(fā)送端主機根據接收端主機的窗口大小進行流量控制。由此也可以防止發(fā)送端主機一次發(fā)送過大數據導致接收端主機無法處理。

如上圖所示,當主機 B 收到報文段 2000 - 2999 之后緩沖區(qū)已滿,不得不暫時停止接收數據。然后主機 A 發(fā)送窗口探測包,窗口探測包非常小僅僅一個字節(jié)。然后主機 B 更新緩沖區(qū)接收窗口大小并發(fā)送窗口更新通知給主機 A,然后主機 A 再繼續(xù)發(fā)送報文段。

在上面的發(fā)送過程中,窗口更新通知可能會丟失,一旦丟失發(fā)送端就不會發(fā)送數據,所以窗口探測包會隨機發(fā)送,以避免這種情況發(fā)生。

連接管理

在繼續(xù)介紹下面有意思的特性之前,我們先來把關注點放在 TCP 的連接管理上,因為沒有 TCP 連接,也就沒有后續(xù)的一系列 TCP 特性什么事兒了。假設運行在一臺主機上的進程想要和另一臺主機上的進程建立一條 TCP 連接,那么客戶中的 TCP 會使用下面這些步驟與服務器中的 TCP 建立連接。

  • 首先,客戶端首先向服務器發(fā)送一個特殊的 TCP 報文段。這個報文段首部不包含應用層數據,但是在報文段的首部中有一個?SYN 標志位?被置為 1。因此,這個特殊的報文段也可以叫做 SYN 報文段。然后,客戶端隨機選擇一個初始序列號(client_isn)?,并將此數字放入初始 TCP SYN 段的序列號字段中,SYN 段又被封裝在 IP 數據段中發(fā)送給服務器。

  • 一旦包含 IP 數據段到達服務器后,服務端會從 IP 數據段中提取 TCP SYN 段,將 TCP 緩沖區(qū)和變量分配給連接,然后給客戶端發(fā)送一個連接所允許的報文段。這個連接所允許的報文段也不包括任何應用層數據。然而,它卻包含了三個非常重要的信息。

這些緩沖區(qū)和變量的分配使 TCP 容易受到稱為 SYN 泛洪的拒絕服務攻擊。

  • 首先,SYN 比特被置為 1 。

  • 然后,TCP 報文段的首部確認號被設置為?client_isn + 1。

  • 最后,服務器選擇自己的初始序號(server_isn),并將其放置到 TCP 報文段首部的序號字段中。

    如果用大白話解釋下就是,我收到了你發(fā)起建立連接的 SYN 報文段,這個報文段具有首部字段 client_isn。我同意建立該連接,我自己的初始序號是 server_isn。這個允許連接的報文段被稱為?SYNACK 報文段

  • 第三步,在收到 SYNACK 報文段后,客戶端也要為該連接分配緩沖區(qū)和變量??蛻舳酥鳈C向服務器發(fā)送另外一個報文段,最后一個報文段對服務器發(fā)送的響應報文做了確認,確認的標準是客戶端發(fā)送的數據段中確認號為 server_isn + 1,因為連接已經建立,所以 SYN 比特被置為 0 。以上就是 TCP 建立連接的三次數據段發(fā)送過程,也被稱為?三次握手

一旦完成這三個步驟,客戶和服務器主機就可以相互發(fā)送報文段了,在以后的每一個報文段中,SYN 比特都被置為 0 ,整個過程描述如下圖所示

40張圖帶你搞懂TCP和UDP

在客戶端主機和服務端主機建立連接后,參與一條 TCP 連接的兩個進程中的任何一個都能終止 TCP 連接。連接結束后,主機中的緩存和變量將會被釋放。假設客戶端主機想要終止 TCP 連接,它會經歷如下過程

客戶應用進程發(fā)出一個關閉命令,客戶 TCP 向服務器進程發(fā)送一個特殊的 TCP 報文段,這個特殊的報文段的首部標志 FIN 被設置為 1 。當服務器收到這個報文段后,就會向發(fā)送方發(fā)送一個確認報文段。然后,服務器發(fā)送它自己的終止報文段,FIN 位被設置為 1 ??蛻舳藢@個終止報文段進行確認。此時,在兩臺主機上用于該連接的所有資源都被釋放了,如下圖所示

40張圖帶你搞懂TCP和UDP

在一個 TCP 連接的生命周期內,運行在每臺主機中的 TCP 協議都會在各種?TCP 狀態(tài)(TCP State)?之間進行變化,TCP 的狀態(tài)主要有?LISTEN、SYN-SEND、SYN-RECEIVED、ESTABLISHED、FIN-WAIT-1、FIN-WAIT-2、CLOSE-WAIT、CLOSING、LAST-ACK、TIME-WAIT 和 CLOSED?。這些狀態(tài)的解釋如下

  • LISTEN: 表示等待任何來自遠程 TCP 和端口的連接請求。

  • SYN-SEND: 表示發(fā)送連接請求后等待匹配的連接請求。

  • SYN-RECEIVED: 表示已接收并發(fā)送連接請求后等待連接確認,也就是 TCP 三次握手中第二步后服務端的狀態(tài)

  • ESTABLISHED: 表示已經連接已經建立,可以將應用數據發(fā)送給其他主機

上面這四種狀態(tài)是 TCP 三次握手所涉及的。

  • FIN-WAIT-1: 表示等待來自遠程 TCP 的連接終止請求,或者等待先前發(fā)送的連接終止請求的確認。

  • FIN-WAIT-2: 表示等待來自遠程 TCP 的連接終止請求。

  • CLOSE-WAIT: 表示等待本地用戶的連接終止請求。

  • CLOSING: 表示等待來自遠程 TCP 的連接終止請求確認。

  • LAST-ACK: 表示等待先前發(fā)送給遠程 TCP 的連接終止請求的確認(包括對它的連接終止請求的確認)。

  • TIME-WAIT: 表示等待足夠的時間以確保遠程 TCP 收到其連接終止請求的確認。

  • CLOSED: 表示連接已經關閉,無連接狀態(tài)。

上面 7 種狀態(tài)是 TCP 四次揮手,也就是斷開鏈接所設計的。

TCP 的連接狀態(tài)會進行各種切換,這些 TCP 連接的切換是根據事件進行的,這些事件由用戶調用:OPEN、SEND、RECEIVE、CLOSE、ABORT 和 STATUS。涉及到 TCP 報文段的標志有?SYN、ACK、RST 和 FIN?,當然,還有超時。

我們下面加上 TCP 連接狀態(tài)后,再來看一下三次握手和四次揮手的過程。

三次握手建立連接

下圖畫出了 TCP 連接建立的過程。假設圖中左端是客戶端主機,右端是服務端主機,一開始,兩端都處于CLOSED(關閉)狀態(tài)。

40張圖帶你搞懂TCP和UDP

  1. 服務端進程準備好接收來自外部的 TCP 連接,一般情況下是調用 bind、listen、socket 三個函數完成。這種打開方式被認為是?被動打開(passive open)。然后服務端進程處于?LISTEN?狀態(tài),等待客戶端連接請求。

  2. 客戶端通過?connect?發(fā)起主動打開(active open),向服務器發(fā)出連接請求,請求中首部同步位 SYN = 1,同時選擇一個初始序號 sequence ,簡寫 seq = x。SYN 報文段不允許攜帶數據,只消耗一個序號。此時,客戶端進入?SYN-SEND?狀態(tài)。

  3. 服務器收到客戶端連接后,,需要確認客戶端的報文段。在確認報文段中,把 SYN 和 ACK 位都置為 1 。確認號是 ack = x + 1,同時也為自己選擇一個初始序號 seq = y。請注意,這個報文段也不能攜帶數據,但同樣要消耗掉一個序號。此時,TCP 服務器進入?SYN-RECEIVED(同步收到)?狀態(tài)。

  4. 客戶端在收到服務器發(fā)出的響應后,還需要給出確認連接。確認連接中的 ACK 置為 1 ,序號為 seq = x + 1,確認號為 ack = y + 1。TCP 規(guī)定,這個報文段可以攜帶數據也可以不攜帶數據,如果不攜帶數據,那么下一個數據報文段的序號仍是 seq = x + 1。這時,客戶端進入?ESTABLISHED (已連接)?狀態(tài)

  5. 服務器收到客戶的確認后,也進入?ESTABLISHED?狀態(tài)。

TCP 建立一個連接需要三個報文段,釋放一個連接卻需要四個報文段。

四次揮手

數據傳輸結束后,通信的雙方可以釋放連接。數據傳輸結束后的客戶端主機和服務端主機都處于 ESTABLISHED 狀態(tài),然后進入釋放連接的過程。

40張圖帶你搞懂TCP和UDP

TCP 斷開連接需要歷經的過程如下

  1. 客戶端應用程序發(fā)出釋放連接的報文段,并停止發(fā)送數據,主動關閉 TCP 連接??蛻舳酥鳈C發(fā)送釋放連接的報文段,報文段中首部 FIN 位置為 1 ,不包含數據,序列號位 seq = u,此時客戶端主機進入?FIN-WAIT-1(終止等待 1)?階段。

  2. 服務器主機接受到客戶端發(fā)出的報文段后,即發(fā)出確認應答報文,確認應答報文中 ACK = 1,生成自己的序號位 seq = v,ack = u + 1,然后服務器主機就進入?CLOSE-WAIT(關閉等待)?狀態(tài),這個時候客戶端主機 -> 服務器主機這條方向的連接就釋放了,客戶端主機沒有數據需要發(fā)送,此時服務器主機是一種半連接的狀態(tài),但是服務器主機仍然可以發(fā)送數據。

  3. 客戶端主機收到服務端主機的確認應答后,即進入?FIN-WAIT-2(終止等待2)?的狀態(tài)。等待客戶端發(fā)出連接釋放的報文段。

  4. 當服務器主機沒有數據發(fā)送后,應用進程就會通知 TCP 釋放連接。這時服務端主機會發(fā)出斷開連接的報文段,報文段中 ACK = 1,序列號 seq = w,因為在這之間可能已經發(fā)送了一些數據,所以 seq 不一定等于 v + 1。ack = u + 1,在發(fā)送完斷開請求的報文后,服務端主機就進入了?LAST-ACK(最后確認)的階段。

  5. 客戶端收到服務端的斷開連接請求后,客戶端需要作出響應,客戶端發(fā)出斷開連接的報文段,在報文段中,ACK = 1, 序列號 seq = u + 1,因為客戶端從連接開始斷開后就沒有再發(fā)送數據,ack = w + 1,然后進入到?TIME-WAIT(時間等待)?狀態(tài),請注意,這個時候 TCP 連接還沒有釋放。必須經過時間等待的設置,也就是?2MSL?后,客戶端才會進入?CLOSED?狀態(tài),時間 MSL 叫做最長報文段壽命(Maximum Segment Lifetime)。

  6. 服務端主要收到了客戶端的斷開連接確認后,就會進入 CLOSED 狀態(tài)。因為服務端結束 TCP 連接時間要比客戶端早,而整個連接斷開過程需要發(fā)送四個報文段,因此釋放連接的過程也被稱為四次揮手。

什么是 TIME-WAIT

我上面只是簡單提到了一下 TIME-WAIT 狀態(tài)和 2MSL 是啥,下面來聊一下這兩個概念。

MSL?是 TCP 報文段可以存活或者駐留在網絡中的最長時間。RFC 793 定義了 MSL 的時間是兩分鐘,但是具體的實現還要根據程序員來指定,一些實現采用了 30 秒的這個最大存活時間。

那么為什么要等待?2MSL?呢?

主要是因為兩個理由

  • 為了保證最后一個響應能夠到達服務器,因為在計算機網絡中,最后一個 ACK 報文段可能會丟失,從而致使客戶端一直處于?LAST-ACK?狀態(tài)等待客戶端響應。這時候服務器會重傳一次?FINACK?斷開連接報文,客戶端接收后再重新確認,重啟定時器。如果客戶端不是 2MSL ,在客戶端發(fā)送 ACK 后直接關閉的話,如果報文丟失,那么雙方主機會無法進入 CLOSED 狀態(tài)。

  • 還可以防止已失效的報文段??蛻舳嗽诎l(fā)送最后一個 ACK 之后,再經過經過 2MSL,就可以使本鏈接持續(xù)時間內所產生的所有報文段都從網絡中消失。從而保證在關閉連接后不會有還在網絡中滯留的報文段去騷擾服務器。

這里注意一點:在服務器發(fā)送了 FIN-ACK 之后,會立即啟動超時重傳計時器。客戶端在發(fā)送最后一個 ACK 之后會立即啟動時間等待計時器。

說好的 RST 呢

說好的?RST、SYN、FIN?標志用于連接的建立和關閉,那么 SYN 和 FIN 都現身了,那 RST 呢?也是啊,我們上面探討的都是一種理想的情況,就是客戶端服務器雙方都會接受傳輸報文段的情況,還有一種情況是當主機收到 TCP 報文段后,其 IP 和端口號不匹配的情況。假設客戶端主機發(fā)送一個請求,而服務器主機經過 IP 和端口號的判斷后發(fā)現不是給這個服務器的,那么服務器就會發(fā)出一個?RST?特殊報文段給客戶端。

40張圖帶你搞懂TCP和UDP

因此,當服務端發(fā)送一個 RST 特殊報文段給客戶端的時候,它就會告訴客戶端沒有匹配的套接字連接,請不要再繼續(xù)發(fā)送了

上面探討的是 TCP 的情況,那么 UDP 呢?

使用 UDP 作為傳輸協議后,如果套接字不匹配的話,UDP 主機就會發(fā)送一個特殊的 ICMP 數據報。

SYN 洪泛攻擊

下面我們來討論一下什么是?SYN 洪泛攻擊。

我們在 TCP 的三次握手中已經看到,服務器為了響應一個收到的 SYN,分配并初始化變量連接和緩存,然后服務器發(fā)送一個 SYNACK 作為響應,然后等待來自于客戶端的 ACK 報文。如果客戶端不發(fā)送 ACK 來完成最后一步的話,那么這個連接就處在一個掛起的狀態(tài),也就是半連接狀態(tài)。

攻擊者通常在這種情況下發(fā)送大量的 TCP SYN 報文段,服務端繼續(xù)響應,但是每個連接都完不成三次握手的步驟。隨著 SYN 的不斷增加,服務器會不斷的為這些半開連接分配資源,導致服務器的連接最終被消耗殆盡。這種攻擊也是屬于?Dos?攻擊的一種。

抵御這種攻擊的方式是使用?SYN cookie?,下面是它的工作流程介紹

  • 當服務器收到一個 SYN 報文段時,它并不知道這個報文段是來自哪里,是來自攻擊者主機還是客戶端主機(雖然攻擊者也是客戶端,不過這么說更便于區(qū)分) 。因此服務器不會為報文段生成一個半開連接。與此相反,服務器生成一個初始的 TCP 序列號,這個序列號是 SYN 報文段的源和目的 IP 地址與端口號這個四元組構造的一個復雜的散列函數,這個散列函數生成的 TCP 序列號就是?SYN Cookie,用于緩存 SYN 請求。然后,服務器會發(fā)送帶著 SYN Cookie 的 SYNACK 分組。有一點需要注意的是,服務器不會記憶這個 Cookie 或 SYN 的其他狀態(tài)信息。

  • 如果客戶端不是攻擊者的話,它就會返回一個 ACK 報文段。當服務器收到這個 ACK 后,需要驗證這個 ACK 與 SYN 發(fā)送的是否相同,驗證的標準就是確認字段中的確認號和序列號,源和目的 IP 地址與端口號以及和散列函數的是否一致,散列函數的結果 + 1 是否和 SYNACK 中的確認值相同。(大致是這樣,說的不對還請讀者糾正) 。如果有興趣讀者可以自行深入了解。如果是合法的,服務器就會生成一個具有套接字的全開連接。

  • 如果客戶端沒有返回 ACK,即認為是攻擊者,那么這樣也沒關系,服務器沒有收到 ACK,不會分配變量和緩存資源,不會對服務器產生危害。

擁塞控制

有了 TCP 的窗口控制后,使計算機網絡中兩個主機之間不再是以單個數據段的形式發(fā)送了,而是能夠連續(xù)發(fā)送大量的數據包。然而,大量數據包同時也伴隨著其他問題,比如網絡負載、網絡擁堵等問題。TCP 為了防止這類問題的出現,使用了?擁塞控制?機制,擁塞控制機制會在面臨網絡擁塞時遏制發(fā)送方的數據發(fā)送。

擁塞控制主要有兩種方法

  • 端到端的擁塞控制: 因為網絡層沒有為運輸層擁塞控制提供顯示支持。所以即使網絡中存在擁塞情況,端系統(tǒng)也要通過對網絡行為的觀察來推斷。TCP 就是使用了端到端的擁塞控制方式。IP 層不會向端系統(tǒng)提供有關網絡擁塞的反饋信息。那么 TCP 如何推斷網絡擁塞呢?如果超時或者三次冗余確認就被認為是網絡擁塞,TCP 會減小窗口的大小,或者增加往返時延來避免。

  • 網絡輔助的擁塞控制: 在網絡輔助的擁塞控制中,路由器會向發(fā)送方提供關于網絡中擁塞狀態(tài)的反饋。這種反饋信息就是一個比特信息,它指示鏈路中的擁塞情況。

下圖描述了這兩種擁塞控制方式

40張圖帶你搞懂TCP和UDP

TCP 擁塞控制

如果你看到這里,那我就暫定認為你了解了 TCP 實現可靠性的基礎了,那就是使用序號和確認號。除此之外,另外一個實現 TCP 可靠性基礎的就是 TCP 的擁塞控制。如果說

TCP 所采用的方法是讓每一個發(fā)送方根據所感知到的網絡的擁塞程度來限制發(fā)出報文段的速率,如果 TCP 發(fā)送方感知到沒有什么擁塞,則 TCP 發(fā)送方會增加發(fā)送速率;如果發(fā)送方感知沿著路徑有阻塞,那么發(fā)送方就會降低發(fā)送速率。

但是這種方法有三個問題

  1. TCP 發(fā)送方如何限制它向其他連接發(fā)送報文段的速率呢?

  2. 一個 TCP 發(fā)送方是如何感知到網絡擁塞的呢?

  3. 當發(fā)送方感知到端到端的擁塞時,采用何種算法來改變其發(fā)送速率呢?

我們先來探討一下第一個問題,TCP 發(fā)送方如何限制它向其他連接發(fā)送報文段的速率呢?

我們知道 TCP 是由接收緩存、發(fā)送緩存和變量(LastByteRead, rwnd,等)組成。發(fā)送方的 TCP 擁塞控制機制會跟蹤一個變量,即?擁塞窗口(congestion window)?的變量,擁塞窗口表示為?cwnd,用于限制 TCP 在接收到 ACK 之前可以發(fā)送到網絡的數據量。而接收窗口(rwnd)?是一個用于告訴接收方能夠接受的數據量。

一般來說,發(fā)送方未確認的數據量不得超過 cwnd 和 rwnd 的最小值,也就是

LastByteSent - LastByteAcked <= min(cwnd,rwnd)

由于每個數據包的往返時間是 RTT,我們假設接收端有足夠的緩存空間用于接收數據,我們就不用考慮 rwnd 了,只專注于 cwnd,那么,該發(fā)送方的發(fā)送速率大概是?cwnd/RTT 字節(jié)/秒?。通過調節(jié) cwnd,發(fā)送方因此能調整它向連接發(fā)送數據的速率。

一個 TCP 發(fā)送方是如何感知到網絡擁塞的呢?

這個我們上面討論過,是 TCP 根據超時或者 3 個冗余 ACK 來感知的。

當發(fā)送方感知到端到端的擁塞時,采用何種算法來改變其發(fā)送速率呢??

這個問題比較復雜,且容我娓娓道來,一般來說,TCP 會遵循下面這幾種指導性原則

  • 如果在報文段發(fā)送過程中丟失,那就意味著網絡擁堵,此時需要適當降低 TCP 發(fā)送方的速率。

  • 一個確認報文段指示發(fā)送方正在向接收方傳遞報文段,因此,當對先前未確認報文段的確認到達時,能夠增加發(fā)送方的速率。為啥呢?因為未確認的報文段到達接收方也就表示著網絡不擁堵,能夠順利到達,因此發(fā)送方擁塞窗口長度會變大,所以發(fā)送速率會變快

  • 帶寬探測,帶寬探測說的是 TCP 可以通過調節(jié)傳輸速率來增加/減小 ACK 到達的次數,如果出現丟包事件,就會減小傳輸速率。因此,為了探測擁塞開始出現的頻率, TCP 發(fā)送方應該增加它的傳輸速率。然后慢慢使傳輸速率降低,進而再次開始探測,看看擁塞開始速率是否發(fā)生了變化。

在了解完 TCP 擁塞控制后,下面我們就該聊一下 TCP 的?擁塞控制算法(TCP congestion control algorithm)?了。TCP 擁塞控制算法主要包含三個部分:慢啟動、擁塞避免、快速恢復,下面我們依次來看一下

慢啟動

當一條 TCP 開始建立連接時,cwnd 的值就會初始化為一個 MSS 的較小值。這就使得初始發(fā)送速率大概是?MSS/RTT 字節(jié)/秒?,比如要傳輸 1000 字節(jié)的數據,RTT 為 200 ms ,那么得到的初始發(fā)送速率大概是 40 kb/s 。實際情況下可用帶寬要比這個 MSS/RTT 大得多,因此 TCP 想要找到最佳的發(fā)送速率,可以通過?慢啟動(slow-start)?的方式,在慢啟動的方式中,cwnd 的值會初始化為 1 個 MSS,并且每次傳輸報文確認后就會增加一個 MSS,cwnd 的值會變?yōu)?2 個 MSS,這兩個報文段都傳輸成功后每個報文段 + 1,會變?yōu)?4 個 MSS,依此類推,每成功一次 cwnd 的值就會翻倍。如下圖所示

40張圖帶你搞懂TCP和UDP

發(fā)送速率不可能會一直增長,增長總有結束的時候,那么何時結束呢?慢啟動通常會使用下面這幾種方式結束發(fā)送速率的增長。

  • 如果在慢啟動的發(fā)送過程出現丟包的情況,那么 TCP 會將發(fā)送方的 cwnd 設置為 1 并重新開始慢啟動的過程,此時會引入一個?ssthresh(慢啟動閾值)?的概念,它的初始值就是產生丟包的 cwnd 的值 / 2,即當檢測到擁塞時,ssthresh 的值就是窗口值的一半。

  • 第二種方式是直接和 ssthresh 的值相關聯,因為當檢測到擁塞時,ssthresh 的值就是窗口值的一半,那么當 cwnd > ssthresh 時,每次翻番都可能會出現丟包,所以最好的方式就是 cwnd 的值 = ssthresh ,這樣 TCP 就會轉為擁塞控制模式,結束慢啟動。

  • 慢啟動結束的最后一種方式就是如果檢測到 3 個冗余 ACK,TCP 就會執(zhí)行一種快速重傳并進入恢復狀態(tài)。

擁塞避免

當 TCP 進入擁塞控制狀態(tài)后,cwnd 的值就等于擁塞時值的一半,也就是 ssthresh 的值。所以,無法每次報文段到達后都將 cwnd 的值再翻倍。而是采用了一種相對保守的方式,每次傳輸完成后只將 cwnd 的值增加一個 MSS,比如收到了 10 個報文段的確認,但是 cwnd 的值只增加一個 MSS。這是一種線性增長模式,它也會有增長逾值,它的增長逾值和慢啟動一樣,如果出現丟包,那么 cwnd 的值就是一個 MSS,ssthresh 的值就等于 cwnd 的一半;或者是收到 3 個冗余的 ACK 響應也能停止 MSS 增長。如果 TCP 將 cwnd 的值減半后,仍然會收到 3 個冗余 ACK,那么就會將 ssthresh 的值記錄為 cwnd 值的一半,進入?快速恢復?狀態(tài)。

快速恢復

在快速恢復中,對于使 TCP 進入快速恢復狀態(tài)缺失的報文段,對于每個收到的冗余 ACK,cwnd 的值都會增加一個 MSS 。當對丟失報文段的一個 ACK 到達時,TCP 在降低 cwnd 后進入擁塞避免狀態(tài)。如果在擁塞控制狀態(tài)后出現超時,那么就會遷移到慢啟動狀態(tài),cwnd 的值被設置為 1 個 MSS,ssthresh 的值設置為 cwnd 的一半。

到這里,我相信你定會收獲。

特別推薦一個分享架構+算法的優(yōu)質內容,還沒關注的小伙伴,可以長按關注一下:

40張圖帶你搞懂TCP和UDP

40張圖帶你搞懂TCP和UDP

40張圖帶你搞懂TCP和UDP

長按訂閱更多精彩▼

40張圖帶你搞懂TCP和UDP

如有收獲,點個在看,誠摯感謝

免責聲明:本文內容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯系我們,謝謝!

本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內容真實性等。需要轉載請聯系該專欄作者,如若文章內容侵犯您的權益,請及時聯系本站刪除。
換一批
延伸閱讀

LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: 驅動電源

在工業(yè)自動化蓬勃發(fā)展的當下,工業(yè)電機作為核心動力設備,其驅動電源的性能直接關系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護是驅動電源設計中至關重要的兩個環(huán)節(jié),集成化方案的設計成為提升電機驅動性能的關鍵。

關鍵字: 工業(yè)電機 驅動電源

LED 驅動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設備的使用壽命。然而,在實際應用中,LED 驅動電源易損壞的問題卻十分常見,不僅增加了維護成本,還影響了用戶體驗。要解決這一問題,需從設計、生...

關鍵字: 驅動電源 照明系統(tǒng) 散熱

根據LED驅動電源的公式,電感內電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關鍵字: LED 設計 驅動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產業(yè)的重要發(fā)展方向。電動汽車的核心技術之一是電機驅動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機驅動系統(tǒng)中的關鍵元件,其性能直接影響到電動汽車的動力性能和...

關鍵字: 電動汽車 新能源 驅動電源

在現代城市建設中,街道及停車場照明作為基礎設施的重要組成部分,其質量和效率直接關系到城市的公共安全、居民生活質量和能源利用效率。隨著科技的進步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關鍵字: 發(fā)光二極管 驅動電源 LED

LED通用照明設計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數校正(PFC)、空間受限和可靠性等。

關鍵字: LED 驅動電源 功率因數校正

在LED照明技術日益普及的今天,LED驅動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關鍵字: LED照明技術 電磁干擾 驅動電源

開關電源具有效率高的特性,而且開關電源的變壓器體積比串聯穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機重量也有所下降,所以,現在的LED驅動電源

關鍵字: LED 驅動電源 開關電源

LED驅動電源是把電源供應轉換為特定的電壓電流以驅動LED發(fā)光的電壓轉換器,通常情況下:LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: LED 隧道燈 驅動電源
關閉