計算機網絡:傳輸層
- 應用層協議:http、https、ftp、dns、smtp、pop3、rdp、telnet、……-
傳輸層協議:TCP、UDP
-
網絡層協議:IP(RIP、OSPF、BGP)、ARP、ICMP、IGMP
5.1、傳輸層的兩個協議
傳輸層也稱為運輸層。
5.1.1、概述
進程之間的通信
- 從通信和信息處理的角度看,傳輸層向它上面的應用層提供通信服務,它屬於面向通信部分的最高層,同時也是用戶功能中的最低層。
- 當網絡的邊緣部分中的兩個主機使用網絡的核心部分的功能進行端到端的通信時,只有位於網絡邊緣部分的主機的協議棧才有傳輸層,而網絡核心部分中的路由器在轉發分組時都只用到下三層的功能。
運輸層為相互通信的應用進程提供了邏輯通信

- 兩個主機進行通信實際上就是兩個主機中的應用進程互相通信。
- 應用進程之間的通信又稱為端到端的通信。
- 運輸層的一個很重要的功能就是復用和分用。應用層不同進程的報文通過不同的端口向下交到運輸層,再往下就共用網絡層提供的服務。
- “運輸層提供應用進程間的邏輯通信”。“邏輯通信”的意思是:運輸層之間的通信好像是沿水平方向傳送數據。但事實上這兩個運輸層之間並沒有一條水平方向的物理連接。
運輸層協議和網絡層協議的主要區別
運輸層協議和網絡層協議的主要區別

運輸層為應用進程之間提供端到端的邏輯通信(但網絡層是為主機之間提供邏輯通信)- 運輸層還要對收到的報文進行差錯檢測
- 運輸層需要有兩種不同的運輸協議,即面向連接的 TCP 和無連接的 UDP
- 運輸層的 UDP 用戶數據報與網際層的 IP 數據報有很大區別。IP 數據報要經過互連網中許多路由器的存儲轉發,但 UDP 用戶數據報是在運輸層的端到端抽中象的邏輯信道中傳送的。
兩種不同的運輸協議
- 運輸層向高層用戶屏蔽了下面網絡核心的細節(如網絡拓撲、所采用的路由選擇協議等),它使應用進程看見的就是好像在兩個運輸層實體之間有一條端到端的邏輯通信信道。
- 當運輸層采用面向連接的 TCP 協議時,盡管下面的網絡是不可靠的(只提供盡最大努力服務),但這種邏輯通信信道就相當於一條全雙工的可靠信道。
- 當運輸層采用無連接的 UDP 協議時,這種邏輯通信信道是一條不可靠信道。
5.1.2、TCP & UDP 協議的應用場景
網絡中的計算機通信無外乎有以下兩種情況:
- 要發送的內容多,需要將發送的內容分成多個數據包發送。
- 要發送的內容少,一個數據包就能發送全部內容。
針對這兩種情況,在傳輸層有兩個協議:
- TCP(Transmission Control Protocol,傳輸控制協議)
- UDP(User Datagram Protocol,用戶數據報協議)
TCP:分段,編號,流量控制,建立會話
UDP:一個數據包就能完成數據通信,不建立會話,多播
TCP & UDP 的關系
- 兩個對等運輸實體在通信時傳送的數據單位叫作
運輸協議數據單元 TPDU (Transport Protocol Data Unit) - TCP 傳送的數據單位是
TCP 報文段(segment) - UDP 傳送的數據單位是
UDP 報文 or 用戶數據報
幾點注意:
-
UDP 在傳送數據之前不需要建立連接。對方的傳輸層在收到 UDP 報文后,不需要給出任何確認。雖然 UDP 不提供可靠交付,但在某些情況下,UDP 是一種最有效的工作方式。
-
TCP 則是面向連接的服務。TCP 不提供廣播或多播服務。由於 TCP 要提供可靠的、面向連接的傳輸服務,因此不可避免地增加了許多的開銷。這不僅使協議數據單元的首部增大很多,還要占用許多的處理機資源。
-
TCP 報文段是在運輸層抽象的端到端邏輯信道中傳送,這種信道是可靠的全雙工信道。但這樣的信道卻不知道究竟經過了哪些路由器,而這些路由器也根本不知道上面的運輸層是否建立了 TCP 連接。
5.1.3、傳輸層的端口
- 運行在計算機中的進程是用進程標識符來標志的。
- 運行在應用層的各種應用進程卻不應當讓計算機操作系統指派它的進程標識符。這是因為在因特網上使用的計算機的操作系統種類很多,而不同的操作系統又使用不同格式的進程標識符。
- 為了使運行不同操作系統的計算機的應用進程能夠互相通信,就必須用統一的方法對 TCP/IP 體系的應用進程進行標志。
需要解決的問題
- 由於進程的創建和撤銷都是動態的,發送方幾乎無法識別其他機器上的進程。
- 有時我們會改換接收報文的進程,但並不需要通知所有發送方。
- 我們往往需要利用目的主機提供的功能來識別終點,而不需要知道實現這個功能的進程。
解決這個問題的方法就是在運輸層使用協議端口號(protocol port number),或通常簡稱為 端口(port)
-
端口用一個 16 位端口號進行標志。
-
端口號只具有本地意義,即端口號只是為了標志本計算機應用層中的各進程。在因特網中不同計算機的相同端口號是沒有聯系的。
雖然通信的終點是應用進程,但我們可以把端口想象是通信的終點,因為我們只要把要傳送的報文交到目的主機的某一個合適的目的端口,剩下的工作(即最后交付目的進程)就由 TCP 來完成。
軟件端口與硬件端口
- 在協議棧層間的抽象的協議端口是軟件端口。
- 路由器或交換機上的端口是硬件端口。
- 硬件端口是不同硬件設備進行交互的接口,而軟件端口是應用層的各種協議進程與運輸實體進行層間交互的一種地址。
端口的分類
按端口號可分為 3 大類:
- 熟知端口(Well Known Ports):數值一般為 0~1023。例如:80 端口實際上總是 HTTP 通訊。
- 注冊端口(Registered Ports):從 1024 到 49151。它們松散地綁定於一些服務。也就是說有許多服務綁定於這些端口,這些端口同樣用於許多其它目的。例如:許多系統處理動態端口從 1024 左右開始。
- 動態和 / 私有端口(Dynamic and/or Private Ports):從 49152 到65535。理論上,不應為服務分配這些端口。實際上,機器通常從 1024起分配動態端口。但也有例外:SUN 的 RPC 端口從 32768 開始。
5.1.4、傳輸層協議和應用層協議之間的關系
- FTP = TCP + 21
- SSH = TCP + 22
- Telnet = TCP + 23
- SMTP = TCP + 25
- DNS = UDP + 53 or TCP(很少) + 53
- HTTP= TCP + 80
- POP3 = TCP + 110
- HTTPS = TCP + 443
- 共享文件夾 = TCP + 445
- SQL Server = TCP + 1433
- MySQL = TCP + 3306
- RDP = TCP + 3389
應用層協議和服務之間的關系:服務運行后會在 TCP or UDP 的某個端口一直偵聽客戶端請求(對外提供的服務偵聽,對內提供的服務不偵聽)
端口代表服務,用端口區分服務
更改端口有利於增加服務器安全

5.1.5、網絡安全知識
Windows 10 系統打開 telnet 服務
# 打開控制面板
control
# 打開 微軟終端服務客戶端,Microsoft terminal services client
mstsc
# 打開防火牆的高級設置
wf.msc
# 打開服務
services.msc
# 打開系統配置實用程序
msconfig



# 測試遠程計算機打開的端口
telnet 192.s168.2.116 21

Windows 10 防火牆的作用
當啟用 Windows 10 防火牆阻止所有傳入連接時,會把所有的端口都關閉,Windows 10 防火牆不攔截出去的流量,但攔截主動進來的流量,出去的流量還可以回來,端口是動態打開和關閉的,此時,你的計算機就相當於在互聯網上隱身了,但還可以訪問外網,可以防止別人掃描你的端口來攻擊你計算機上安裝的服務。
打開 Windows 10 防火牆 阻止所有傳入連接操作步驟:
第一步:打開控制面板 --> 點擊 系統和安全
第二步:點擊 Windows Defender 防火牆



第三步:測試:
① 讓另一台計算機 ping 本計算機的 IP 地址,發現 ping 不通

② 本計算機 ping www.baidu.com 可以 ping 通

取消勾選時,發現可以 ping 通了!
灰鴿子木馬
一般來說,是客戶端主動連接服務器,但木馬程序是木馬服務主動連接客戶端,如果計算機一旦中了木馬,Windows 防火牆不能防控木馬程序!
Windows 系統可以指定 安全策略,例如可以讓主動進入且目標端口為 80 進,讓出去且源端口為 80 的出,這時木馬就只是一段運行着的代碼,無法與外界客戶端取得連接,被堵在里
面,沒有威脅!


5.2、用戶數據報協議 UDP
5.2.1、UDP 協議的特點
1)、UDP 是無連接的,即發送數據之前不需要建立連接(當然發送數據結束時也沒有連接可釋放),因此減少了開銷和發送數據之前的時延。
2)、UDP 使用盡最大努力交付,即不保證可靠交付,因此主機不需要維持復雜的連接狀態表(這里面有許多參數),通信的兩端不用保持連接,因此節省系統資源。
3)、UDP 是面向報文的,發送方的 UDP 對應用程序交下來的報文,在添加首部后就向下交付給網絡層。UDP 對應用層交下來的報文,既不合並,也不拆分,而是保留這些報文的邊界。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-W0VJs1iK-1596446046744)(計算機網絡05:傳輸層.assets/image-20200801145940333.png)]
4)、UDP 沒有擁塞控制,即使網絡出現的擁塞也不會使源主機的發送速率降低。這對某些實時應用是很重要的。
5)、UDP 支持一對一、一對多、多對一和多對多的交互通信。
6)、UDP 的首部開銷小,只有 8 個字節,比 TCP 的 20 個字節的首部要短。
5.2.2、UDP 的首部格式

UDP 的首部包括四個字段,每個字段的長度是 2 個字節,因此首部共 8 個 字節。
- 源端口:源端口號。在需要對方回信時選用。不需要時可用全 0
- 目標端口:目的端口號。在終點交付報文時使用。
- 長度:UDP 用戶數據報的長度,其最小值是 8(僅有首部)。
- 校驗和:檢測 UDP 用戶數據報在傳輸中是否有錯。有錯就丟棄。
如果接收方 UDP 發現收到的報文中的目的端口號不正確(即不存在對應於該端口號的應用進程),就丟棄該報文,並由網際控制報文協議 ICMP 發送“端口不可達”差錯報文給發送方。
雖然在 UDP 之間的通信要用到其端口號,但由於 UDP 的通信是無連接的,因此不需要使用套接字(TCP 之間的通信必須要在兩個套接字之間建立連接)。
UDP 用戶數據報首部中檢驗和的計算方法很特殊。
偽首部包括:源地址、目的地址、UDP數據長度、協議類型(0x11),協議類型就一個字節,但需要在前補一個字節的 0x0,構成 12 個字節。
在計算檢驗和時,要在UDP 用戶數據報之前增加 12 個字節的偽首部。所謂“偽首部”是因為這種偽首部並不是 UDP 用戶數據報的真正的首部。只是在計算檢驗和時臨時添加在UDP用戶數據報前面,得到一個臨時的 UDP 用戶數據報。
檢驗和就是按照這個臨時的 UDP 用戶數據報來計算的。偽首部既不向下傳送也不向上遞交,而僅僅是為了計算檢驗和。

5.3、傳輸控制協議 TCP
- TCP 協議的特點?
- TCP 協議首部格式?
- TCP 協議是如何實現可靠傳輸?
- TCP 協議是如何實現流量控制?
- TCP 協議是如何避免網絡擁塞?
5.3.1、TCP 協議特點
-
TCP 是面向連接的傳輸層協議。
-
在傳送數據完畢后,必須釋放已經建立的 TCP 連接。這就是說,應用進程之間的通信好像在“打電話”:通話前要先撥號建立連接,通話結束后要掛機釋放連接。
-
每一條 TCP 連接只能有兩個端點(endpoint),每一條 TCP 連接只能是點對點的(一對一,單播)。
-
-
TCP 提供可靠交付的服務。
-
也就是說,通過 TCP 連接傳送的數據,無差錯、不丟失、不重復、且按序發送。
-
TCP 提供全雙工通信。
- TCP 允許通信雙方的應用進程可以同時發送和接受數據。
- TCP 連接的兩端都設有 TCP 發送緩存 和 TCP 接收緩存,用來臨時存放雙向通信的數據。
- 在發送時,應用程序把即將發送的數據發送到給 TCP 發送緩存后,就可以做自己的事,而 TCP 在合適的時候把數據發送出去。
- 在接收時,TCP 把收到的數據放入 TCP 接受緩存中,上層的應用進程在合適的時候讀取緩存中的數據。
-
面向字節流。
- TCP 中的“流”(steam)指的是 流入到進程 或 從進程流出的字節 序列。

注意:
- TCP 連接是一條虛連接而不是一條真正的物理連接。
- TCP 對應用進程一次把多長的報文發送到 TCP 的緩存中是不關心的。
- TCP 根據對方給出的窗口值和當前網絡擁塞的程度來決定一個報文段應包含多少個字節(UDP 發送的報文長度是應用進程給出的)。
- TCP 可把太長的數據塊划分短一些再傳送。
- TCP 也可等待積累有足夠多的字節后再構成報文段發送出去。
TCP 的連接
-
TCP 把連接作為最基本的抽象。
-
每一條 TCP 連接有兩個端點。TCP 連接的端點叫做 套接字(socket)或插口。
-
TCP 連接的端點不是主機,不是主機的 IP 地址,不是應用進程,也不是傳輸層的協議端口。而是 IP 地址 + 端口。
-
每一條 TCP 連接唯一地被通信兩端的兩個端點(即套接字)所確定。

5.3.2、TCP 首部格式
TCP 協議是能夠實現數據分段傳輸、可靠傳輸、流量控制、網絡擁塞避免等功能,因此 TCP 報文的首部要比 UDP 報文首部字段要多,並且首部長度不固定。

TCP 報文段中各字段的意義
-
源端口(Source Port):占 2 個字節
-
目標端口(Destination Port):占 2 個字節
-
序號(Sequence number,seq):占 4 個字節,發送的數據部分(段)的第一個字節的位置
-
確認號(Acknowledgment number,ack):占 4 個字節,告訴發送者下一次該發第幾個字節了

- 數據偏移(即首部長度):占 4 位,記錄 TCP 報文段從多少個字節以后就開始有數據了
- 因為 TCP 報文段的首部有固定部分(前 20 個字節),也有可選部分,所以要用數據偏移來標記從多少個字節開始就是數據了。
- 保留:占 6 位,保留為今后使用,但目前應置為 0。
- 標志位(Flags):

-
窗口(Window size value):占 2 字節。窗口值是 [0,216-1] 之間的整數。TCP 協議有流量控制功能,窗口值告訴對方:從本報文段首部中的確認號算起,接收方目前允許對方發送的數據量(單位是字節)。
-
檢驗和(Check sum):占 2 字節。檢驗和字段檢驗的范圍包括首部和數據這兩部分。和 UDP 用戶數據報一樣,在計算檢驗和時,要在 TCP 報文段的前面加上 12 字節的偽首部。
-
緊急指針(Urgent pointer):占 2 字節。緊急指針僅在 URG = 1 時才有意義,它指出本報文段中的緊急數據的字節數(緊急數據結束后就是普通數據)。因此緊急指針指出了緊急數據的下一個字節在報文段中的位置。
-
選項(Options):長度可變,最長可達 40 個字節。當沒有使用選項時,TCP 的首部長度是 20 字節。
- TCP 最初只規定了一種選項,即最大報文段長度 MSS(Maximum Segment Size)。
- MSS 告訴對方 TCP:“我的緩存所能接收的報文段的數據字段的最大長度是 MSS 個字節。”
MSS (Maximum Segment Size) 是 TCP 報文段中的數據字段的最大長度。
數據字段 + TCP 首部才等於整個的 TCP 報文段。
-
填充字段: 這是為了使整個首部長度是 4 字節的整數倍。
其他選項
- 窗口擴大選項:占 3 字節,其中有一個字節表示移位值 S。新的窗口值等於 TCP 首部中的窗口位數增大到(16 + S),相當於把窗口值向左移動 S 位后獲得實際的窗口大小。
- 時間戳選項:占10 字節,其中最主要的字段時間戳值字段(4 字節)和時間戳回送回答字段(4 字節)。
- 選擇確認選項
5.4、可靠傳輸的工作原理
網絡層是不可靠的,只負責把一個數據包從一個網段轉到另外一個網段,數據包丟了是不管的,可靠傳輸是由傳輸層實現的。
5.4.1、停止等待協議

- 在發送完一個分組后,必須暫時保留已發送的分組的副本。
- 分組和確認分組都必須進行編號。
- 超時計時器的重傳時間應當比數據在分組傳輸的平均往返時間更長一些。

只要你沒有告訴我你收到了,我就認為你沒收到,我就重傳
使用上述的確認和重傳機制,我們就可以在不可靠的傳輸網絡上實現可靠的通信。
這種可靠傳輸協議常稱為:[自動重傳請求](ARQ,Automatic Repeat reQuest)
ARQ 表明重傳的請求是[自動]進行的。接收方不需要請求發送方重傳某個出錯的分組。
信道利用率
- 停止等待協議的優點是簡單,但缺點是信道利用率太低。

\(信道利用率:U = \frac{T_D}{T_D + RTT + T_A}\)
流水線傳輸
- 發送方可連續發送多個分組,不必每發完一個分組就停頓下來等待對方的確認。
- 由於信道上一直有數據不間斷地傳送,這種傳輸方式可獲得很高的信道利用率。

5.4.2、連續的 ARQ 協議

累積確認
-
接收方一般采用 累積確認 的方式。即不必對收到的分組逐個發送確認,而是對按序到達且連續的最后一個分組發送確認,這樣就表示:
到這個分組為止的所有分組都已正確收到了。 -
累積確認有的優點是:容易實現
-
缺點是:不能向發送方反映出接收方已經正確收到的所有分組的信息。
Go-back-N(回退 N)
- 如果發送方發送了前 5 個分組,而中間的第 3 個分組丟失了。這時接收方只能對前兩個分組發出確認。
- 發送方無法知道后面三個分組的下落,而只好把后面的三個分組都再重傳一次。
- 這就叫做 Go-back-N(回退 N),表示需要再退回來重傳已發送過的 N 個分組。
- 可見當通信線路質量不好時,連續 ARQ 協議會帶來負面的影響。
TCP 可靠通信的具體實現
- TCP 連接的每一端都必須設有兩個窗口——一個發送窗口和一個接收窗口。
- TCP 的可靠傳輸機制用字節的序號進行控制。TCP 所有的確認都是基於序號而不是基於報文段。
- TCP 兩端的四個窗口經常處於動態變化之中。
- TCP連接的往返時間 RTT 也不是固定不變的。需要使用特定的算法估算較為合理的重傳時間。
5.5、可靠傳輸的具體實現
5.5.1、以字節為單位的滑動窗口技術






發送緩存與接收緩存的作用
- 發送緩存用來暫時存放:
- 發送應用程序傳送給發送方 TCP 准備發送的數據;
- TCP 已發送出但尚未收到確認的數據。
- 接收緩存用來暫時存放:
- 按序到達的、但尚未被接收應用程序讀取的數據;
- 不按序到達的數據。
注意:
- A 的發送窗口並不總是和 B 的接收窗口一樣大(因為有一定的時間滯后)。
- TCP 標准沒有規定對不按序到達的數據應如何處理。通常是先臨時存放在接收窗口中,等到字節流中所缺少的字節收到后,再按序交付上層的應用進程。
- TCP 要求接收方必須有累積確認的功能,這樣可以減小傳輸開銷。
5.5.2、超時重傳時間的選擇
- 重傳機制是 TCP 中最重要和最復雜的問題之一。
- TCP 每發送一個報文段,就對這個報文段設置一次計時器。只要計時器設置的重傳時間到但還沒有收到確認,就要重傳這一報文段。
往返時延的方差很大
由於 TCP 的下層是一個互聯網環境,IP 數據報所選擇的路由變化很大。因而運輸層的往返時間的方差也很大。

加權平均往返時間 \(RTT_s\)
- TCP 保留了 RTT 的一個加權平均往返時間 RTTS(這又稱為平滑的往返時間)。
- 第一次測量到 RTT 樣本時,RTTS 值就取為所測量到的 RTT 樣本值。以后每測量到一個新的 RTT 樣本,就按下式重新計算一次 RTTS:
\(新的 RTT_s = (1 - α) × (舊的 RTT_s) + α × (新的 RTT 樣本)\)
- 式中, \(0 ≤ α <1\)
- 若 α 很接近於零,表示 RTT 值更新較慢。
- 若選擇 α 接近於 1,則表示 RTT 值更新較快。
- RFC 2988 推薦的 α 值為 1/8,即 0.125。
超時重傳時間 \(RTO\) (RetransmissionTime-Out)
- \(RTO\) 應略大於上面得出的加權平均往返時間 \(RTT_S\)。
- RFC 2988 建議使用下式計算 RTO:\(RTO = RTTS + 4 × RTT_D\)
- \(RTT_D\) 是 \(RTT\) 的偏差的加權平均值。
- RFC 2988 建議這樣計算 \(RTT_D\) 。第一次測量時,\(RTT_D\) 值取為測量到的 \(RTT\) 樣本值的一半。在以后的測量中,則使用下式計算加權平均的 \(RTT_D:\)
- $新的 RTT_D = (1 - β) × (舊的 RTT_D) + β × | RTT_s - 新的 RTT 樣本 | $
- β 是個小於 1 的系數,其推薦值是 1/4,即 0.25。
往返時間的測量相當復雜
- TCP 報文段 1 沒有收到確認。重傳(即報文段 2)后,收到了確認報文段 ACK。
- 如何判定此確認報文段是對原來的報文段 1 的確認,還是對重傳的報文段 2 的確認?

Karn 算法
- 在計算平均往返時間 RTT 時,只要報文段重傳了,就不采用其往返時間樣本。
- 這樣得出的加權平均平均往返時間 \(RTT_S\) 和超時重傳時間 \(RTO\) 就較准確。
修正的 Karn 算法
- 報文段每重傳一次,就把 RTO 增大一些:
- $新的 RTO = γ × (舊的 RTO) $
- 系數 γ 的典型值是 2 。
- 當不再發生報文段的重傳時,才根據報文段的往返時延更新平均往返時延 \(RTT\) 和超時重傳時間 \(RTO\) 的數值。
- 實踐證明,這種策略較為合理。
5.5.3、選擇確認 SACK(Selective ACK)
- 接收方收到了和前面的字節流不連續的兩個字節塊。
- 如果這些字節的序號都在接收窗口之內,那么接收方就先收下這些數據,但要把這些信息准確地告訴發送方,使發送方不要再重復發送這些已收到的數據。

RFC 2018 的規定
- 如果要使用選擇確認,那么在建立 TCP 連接時,就要在 TCP 首部的選項中加上“允許 SACK”的選項,而雙方必須都事先商定好。
- 如果使用選擇確認,那么原來首部中的“確認號字段”的用法仍然不變。只是以后在 TCP 報文段的首部中都增加了 SACK 選項,以便報告收到的不連續的字節塊的邊界。
- 由於首部選項的長度最多只有 40 字節,而指明一個邊界就要用掉 4 字節,因此在選項中最多只能指明 4 個字節塊的邊界信息。
5.6、TCP 的流量控制
流量控制解決的是通信兩端處理速度不一致問題的!
流量控制是通過接收端告訴發送端接收窗口的大小來控制的!
5.6.1、利用滑動窗口實現流量控制

持續計時器 (persistence timer)
- TCP 為每一個連接設有一個持續計時器。
- 只要 TCP 連接的一方收到對方的零窗口通知,就啟動持續計時器。
- 若持續計時器設置的時間到期,就發送一個零窗口探測報文段(僅攜帶 1 字節的數據),而對方就在確認這個探測報文段時給出了現在的窗口值。
- 若窗口仍然是零,則收到這個報文段的一方就重新設置持續計時器。
- 若窗口不是零,則死鎖的僵局就可以打破了。
5.6.2、必須考慮傳輸效率
可以用不同的機制來控制 TCP 報文段的發送時機:
- 第一種機制是 TCP 維持一個變量,它等於最大報文段長度 MSS。只要緩存中存放的數據達到 MSS 字節時,就組裝成一個 TCP 報文段發送出去。
- 第二種機制是由發送方的應用進程指明要求發送報文段,即 TCP 支持的推送(push)操作。
- 第三種機制是發送方的一個計時器期限到了,這時就把當前已有的緩存數據裝入報文段(但長度不能超過 MSS)發送出去。
5.7、TCP 的擁塞控制
5.7.1、擁塞控制的一般原理
擁塞控制
- 在某段時間,若對網絡中某資源的需求超過了該資源所能提供的可用部分,網絡的性能就要變壞——產生擁塞(congestion)。
- 出現資源擁塞的條件: 對資源需求的總和 > 可用資源
- 若網絡中有許多資源同時產生擁塞,網絡的性能就要明顯變壞,整個網絡的吞吐量將隨輸入負荷的增大而下降。
擁塞控制與流量控制的關系
- 擁塞控制所要做的都有一個前提,就是網絡能夠承受現有的網絡負荷。
- 擁塞控制是一個全局性的過程,涉及到所有的主機、所有的路由器,以及與降低網絡傳輸性能有關的所有因素。
- 流量控制往往指在給定的發送端和接收端之間的點對點通信量的控制。
- 流量控制所要做的就是抑制發送端發送數據的速率,以便使接收端來得及接收。
擁塞控制所起的作用

開環控制和閉環控制
- 開環控制方法就是在設計網絡時事先將有關發生擁塞的因素考慮周到,力求網絡在工作時不產生擁塞。
- 閉環控制是基於反饋環路的概念。屬於閉環控制的有以下幾種措施:
- 監測網絡系統以便檢測到擁塞在何時、何處發生。
- 將擁塞發生的信息傳送到可采取行動的地方。
- 調整網絡系統的運行以解決出現的問題。
5.7.2、幾種擁塞控制方法
1、慢開始和擁塞避免
發送方維持一個叫做擁塞窗口 cwnd (congestion window) 的狀態變量。擁塞窗口的大小取決於網絡的擁塞程度,並且動態地在變化。發送方讓自己的發送窗口等於擁塞窗口。如再考慮到接收方的接收能力,則發送窗口還可能小於擁塞窗口。
發送方控制擁塞窗口的原則是:只要網絡沒有出現擁塞,擁塞窗口就再增大一些,以便把更多的分組發送出去。但只要網絡出現擁塞,擁塞窗口就減小一些,以減少注入到網絡中的分組數。
慢開始算法的原理
- 在主機剛剛開始發送報文段時可先設置擁塞窗口 cwnd = 1,即設置為一個最大報文段 MSS 的數值。
- 在每收到一個對新的報文段的確認后,將擁塞窗口加 1,即增加一個 MSS 的數值。
- 用這樣的方法逐步增大發送端的擁塞窗口 cwnd,可以使分組注入到網絡的速率更加合理。

傳輸輪次 (transmission round)
- 使用慢開始算法后,每經過一個傳輸輪次,擁塞窗口 cwnd 就加倍。
一個傳輸輪次所經歷的時間其實就是往返時間 RTT。 “傳輸輪次”更加強調:把擁塞窗口 cwnd 所允許發送的報文段都連續發送出去,並收到了對已發送的最后一個字節的確認。- 例如,擁塞窗口 cwnd = 4,這時的往返時間 RTT 就是發送方連續發送 4 個報文段,並收到這 4 個報文段的確認,總共經歷的時間。
設置慢開始門限狀態變量 ssthresh
ssthresh——慢啟動閾值
慢開始門限 ssthresh 的用法如下:
- 當 cwnd < ssthresh 時,使用慢開始算法。
- 當 cwnd > ssthresh 時,停止使用慢開始算法而改用擁塞避免算法。
- 當 cwnd = ssthresh 時,既可使用慢開始算法,也可使用擁塞避免算法。
擁塞避免算法的思路是讓擁塞窗口 cwnd 緩慢地增大,即每經過一個往返時間 RTT 就把發送方的擁塞窗口 cwnd 加 1,而不是加倍,使擁塞窗口 cwnd 按線性規律緩慢增長。
無論在慢開始階段還是在擁塞避免階段,只要發送方判斷網絡出現擁塞(其根據就是沒有按時收到確認),就要把慢開始門限 ssthresh 設置為出現擁塞時的發送方窗口值的一半(但不能小於2)。
然后把擁塞窗口 cwnd 重新設置為 1,執行慢開始算法。
這樣做的目的就是要迅速減少主機發送到網絡中的分組數,使得發生擁塞的路由器有足夠時間把隊列中積壓的分組處理完畢。
慢開始和擁塞避免算法的實現舉例

當 TCP 連接進行初始化時,將擁塞窗口置為 1。圖中的窗口單位不使用字節而使用報文段。
慢開始門限的初始值設置為 16 個報文段,即 ssthresh = 16。
發送端的發送窗口不能超過擁塞窗口 cwnd 和接收端窗口 rwnd 中的最小值。我們假定接收端窗口足夠大,因此現在發送窗口的數值等於擁塞窗口的數值。
在執行慢開始算法時,擁塞窗口 cwnd 的初始值為 1,發送第一個報文段 M0。
發送端每收到一個確認 ,就把 cwnd 加 1。於是發送端可以接着發送 M1 和 M2 兩個報文段。
接收端共發回兩個確認。發送端每收到一個對新報文段的確認,就把發送端的 cwnd 加 1。現在 cwnd 從 2 增大到 4,並可接着發送后面的 4 個報文段。
發送端每收到一個對新報文段的確認,就把發送端的擁塞窗口加 1,因此擁塞窗口 cwnd 隨着傳輸輪次按指數規律增長。

當擁塞窗口 cwnd 增長到慢開始門限值 ssthresh 時(即當 cwnd = 16 時),就改為執行擁塞避免算法,擁塞窗口按線性規律增長。

假定擁塞窗口的數值增長到 24 時,網絡出現超時,表明網絡擁塞了。

更新后的 ssthresh 值變為 12(即發送窗口數值 24 的一半),擁塞窗口再重新設置為 1,並執行慢開始算法。

當 cwnd = 12 時改為執行擁塞避免算法,擁塞窗口按按線性規律增長,每經過一個往返時延就增加一個 MSS 的大小。
乘法減小 (multiplicative decrease)
- “乘法減小“是指不論在慢開始階段還是擁塞避免階段,只要出現一次超時(即出現一次網絡擁塞),就把慢開始門限值 ssthresh 設置為當前的擁塞窗口值乘以 0.5。
- 當網絡頻繁出現擁塞時,ssthresh 值就下降得很快,以大大減少注入到網絡中的分組數。
加法增大 (additive increase)
“加法增大”是指執行擁塞避免算法后,在收到對所有報文段的確認后(即經過一個往返時間),就把擁塞窗口 cwnd增加一個 MSS 大小,使擁塞窗口緩慢增大,以防止網絡過早出現擁塞。
注意:
- “擁塞避免”並非指完全能夠避免了擁塞。利用以上的措施要完全避免網絡擁塞還是不可能的。
- “擁塞避免”是說在擁塞避免階段把擁塞窗口控制為按線性規律增長,使網絡比較不容易出現擁塞。
2、快重傳和快恢復
快重傳算法
- 快重傳算法首先要求接收方每收到一個失序的報文段后就立即發出重復確認。這樣做可以讓發送方及早知道有報文段沒有到達接收方。
- 發送方只要一連收到三個重復確認就應當立即重傳對方尚未收到的報文段。
- 不難看出,快重傳並非取消重傳計時器,而是在某些情況下可更早地重傳丟失的報文段。

快恢復算法
1)、當發送端收到連續三個重復的確認時,就執行“乘法減小”算法,把慢開始門限 ssthresh 減半。但接下去不執行慢開始算法。
2)、由於發送方現在認為網絡很可能沒有發生擁塞,因此現在不執行慢開始算法,即擁塞窗口 cwnd 現在不設置為 1,而是設置為慢開始門限 ssthresh 減半后的數值,然后開始執行擁塞避免算法(“加法增大”),使擁塞窗口緩慢地線性增大。

發送窗口的上限值
發送方的發送窗口的上限值應當取為接收方窗口 rwnd 和擁塞窗口 cwnd 這兩個變量中較小的一個,即應按以下公式確定:
發送窗口的上限值:\(發送窗口的上限值 = Min[rwnd, cwnd]\)
- 當 rwnd < cwnd 時,是接收方的接收能力限制發送窗口的最大值。
- 當 cwnd < rwnd 時,則是網絡的擁塞限制發送窗口的最大值。
5.8、TCP 傳輸連接管理
建議看這一篇轉載的文章:https://blog.csdn.net/qq_43591881/article/details/107768812
運輸連接就有三個階段,即:連接建立、數據傳送和連接釋放。運輸連接的管理就是使運輸連接的建立和釋放都能正常地進行。
連接建立過程中要解決以下三個問題:
- 要使每一方能夠確知對方的存在。
- 要允許雙方協商一些參數(如最大報文段長度,最大窗口大小,服務質量等)。
- 能夠對運輸實體資源(如緩存大小,連接表中的項目等)進行分配。
5.8.1、TCP 連接建立——三次握手
- TCP 連接的建立都是采用客戶服務器方式。
- 主動發起連接建立的應用進程叫做客戶(client)。
- 被動等待連接建立的應用進程叫做服務器(server)。

- A 的 TCP 向 B 發出連接請求報文段,其首部中的同步位 SYN = 1,並選擇序號 seq = x,表明傳送數據時的第一個數據字節的序號是 x。
- B 的 TCP 收到連接請求報文段后,如同意,則發回確認。
- B 在確認報文段中應使 SYN = 1,使 ACK = 1, 其確認號ack = x + 1,自己選擇的序號 seq = y。

- A 收到此報文段后向 B 給出確認,其 ACK = 1,確認號 ack = y + 1。
- A 的 TCP 通知上層應用進程,連接已經建立。
- B 的 TCP 收到主機 A 的確認后,也通知其上層應用進程:TCP 連接已經建立。
確認雙方可發送並且可接受,最少需要 3 次通信。
前兩個數據包無法證明客戶端的接受能力時正常的。
抓包時相對序列號是從 0 開始的,但是真實的序列號不是從 0 開始的。
必須得有第三次握手,才能讓服務器知道客戶端的狀態也是建立好的狀態。
就跟打電話一樣
A:“你聽到了嗎?”
B:“我聽到了”
A:“那就好”
Q:TCP 傳輸連接的建立為什么要經過三次握手,而不是兩次握手,也就是第三次握手存在的意義是什么?
A:下面假設了一種情景
1、客戶端 A 給服務器 B 發送一個建立會話的同步請求,但這個請求可能會走比較遠的路由,到達的時間可能會比較長一點,經過了比一個 RTT 時間多一點后,客戶端發現還沒有收到回應,這時客戶端 A 再給服務器 B 發送一個請求,這次服務器立刻就收到了,給了客戶端 A 一個回應,前兩次請求足夠讓客戶端 A 和服務器 B 協商一些參數。
2、這時如果服務器 B 又收到了那個經過比較遠的路由發送的同步請求,服務器 B 呢,又會給客戶端 A 發送一個確認,但此時客戶端 A 已經和服務器 B 建立會話了,所以客戶端 A 它不會搭理服務器 B 這一次的確認,而服務器 B 會一直在等客戶端 A 的確認,就會造成服務器資源的浪費。
3、如果沒有第三次確認,服務器 B 就不知道客戶端 A 是否已經收到了我的確認,會話是否已經建立了。
5.8.2、三次握手建立 TCP 連接的各狀態
| 狀態 | 含義 |
|---|---|
| LISTEN | 表示 socket 已經處於 listen 狀態了,可以建立連接; |
| SYN-SENT | 表示 socket 在發出 connect 連接的時候,會首先發送SYN報文,然后等待另一端發送的確認報文 (ACK),表示這端已經發送完 SYN 報文了; |
| SYN-RCVD | 表示一端已經接收到 SYN 報文了; |
| ESTAB-LISHED | 表示已經建立連接了,可以發送數據了。 |
| CLOSED | 這個狀態表示連接已經斷開。 |

Q:如何在客戶端查看會話的 SYN-SENT 狀態呢?
A:訪問一個不存在的地址,會話請求發出去了,但該地址不存在服務器,服務器也就沒有發送確認了,此時客戶端會話的狀態即為:SYN-SENT
提前打開命令提示符提前輸入:netstat -n

介紹一下 SYN 攻擊器
SYN 攻擊器是通過 TCP 建立連接的特點,也就是客戶端向服務器發送建立連接的請求,對於發送方來說,這個請求里可以偽造源 IP 地址。服務器要給客戶端一個確認,對於接收方來說,目標 IP 地址是偽造,也就無法獲得客戶端的確認,從而服務器會話狀態一直處於接收狀態,即 SYN-RCVD
從而一直浪費服務器資源,攻擊次數和強度足夠大時,導致宕機。
Q:如何在服務端查看會話的 SYN-RCVD狀態呢?
A:操作都要在虛擬機中進行,通過一台電腦使用 SYN 攻擊器攻擊另一台服務器,來查看服務器會話狀態。

5.8.3、TCP 連接釋放——四次揮手

- 數據傳輸結束后,通信的雙方都可釋放連接。
- 現在 A 的應用進程先向其 TCP 發出連接釋放報文段,並停止再發送數據,主動關閉 TCP 連接。
- A 把連接釋放報文段首部的 FIN = 1,其序號 seq = u,等待 B 的確認。

- B 發出確認,確認號 ack = u + 1,而這個報文段自己的序號 seq = v。
TCP 服務器進程通知高層應用進程,A 通向 B 方向的連接已經釋放。 - 從 A 到 B 這個方向的連接就釋放了,TCP 連接處於半關閉狀態。B 若發送數據,A 仍要接收。

- 若 B 已經沒有要向 A 發送的數據,其應用進程就通知 TCP 釋放連接。

- A 收到連接釋放報文段后,必須發出確認。
還是跟打電話一樣
A:“我說完了”
B:“收到”
B:“我也說完了”
A:“收到”
5.8.4、四次揮手釋放 TCP 連接的各狀態
| 狀態 | 含義 |
|---|---|
| ESTAB-LISHED | 這個狀態表示連接已經建立。 |
| FIN-WAIT-1 | 表示在等待另一方的 FIN 報文,和 FIN_WAIT_2 的區別是,FIN_WAIT_1 表示 socket 現在要主動關閉連接,在發送完 FIN 報文后 socket 進入 FIN_WAIT_1 狀態,當收到另一方發送 FIN 的 ACK 之后立即進入 FIN_WAIT_2 狀態; |
| FIN-WAIT-2 | 同上,此時需要做的事情是可能還會接收數據,然后等待另一方的 FIN;也就是說此時發送的通路已斷,接收的通路還是正常的。 |
| TIME-WAIT | 存在主動關閉的一方,表示收到了對方的 FIN 報文,並發送出了 ACK 報文,就等 2MSL(Max Segment Lifetime) 后即可回到 CLOSED 可用狀態了,需要等一段時間時原因是網絡是不可靠的,不能保證這個 ACK 發送成功了,如果失敗了,對端會超時重傳 FIN; |
| CLOSING | 表示在發送 FIN 之后,沒有收到對方的 ACK,而是收到了對方的 FIN,這中情況很少見,只有在兩端幾乎同時關閉同一個socket 的時候才會出現 CLOSING 狀態; |
| CLOSE-WAIT | 表示收到對方的 FIN 之后,回給對方 ACK,此時處於CLOSE_WAIT 狀態,等待關閉,要看自己是否還有數據要發送; |
| LAST-ACK | 表示收到對方的 FIN 之后,回給對方 ACK,然后自己也要關閉發送 FIN ,等待另一方的 ACK 時候的狀態; |
| CLOSED | 這個狀態表示連接已經斷開。 |


注:TCP 連接必須經過時間 2MSL 后才真正釋放掉。
MSL(Maximum Segment Lifetime): 報文最大生存時間,報文最長壽命
Windows: MSL = 2min
linux(Ubuntu, CentOs): MSL = 60s
Unix: MSL = 30s
Q:為什么第四次揮手后客戶端還要等待 2MSL 的時間,而不立刻 CLOSED呢?
A:
如果沒有 2MSL 的等待時間的話,客戶端立刻 CLOSED,一旦客戶端發送的確認包丟失,而服務器未收到確認,會一直發送請求釋放連接的數據包,而這時客戶端已經關閉會話了,使得服務器這端的會話一直處於 LAST-ACK 狀態,從而就無法關閉這次會話。
如果有 2MSL 的等待時間的話,如果客戶端發的確認包丟失了,在這 2MSL 的時間內,服務器向我再次發送請求釋放連接的數據包,我就能再次發送確認。
