【網絡編程】KCP——可靠的 UDP 傳輸協議——的知識匯總

文章目錄

  • 前言
  • UDP 協議
    • UDP 的關鍵指標/特性
    • UDP 的典型應用場景
  • KCP 協議的基礎
    • KCP 的構造
    • KCP 協議特性
  • KCP 的可靠傳輸機制——ARQ
    • 三種 ARQ 機制對比
    • KCP 的選擇性重傳
    • 一、基礎機制:選擇性重傳(SR)
    • 二、KCP 對 SR 的增強策略
  • KCP 的激進重傳策略——低延遲設計!
    • **1、 快速重傳 (Fast Retransmit):跳過漫長的等待**
    • **2、選擇性重傳 (Selective Repeat / SACK-like Behavior):精準打擊,避免浪費**
    • 低延遲 ACK 機制能綜合實現 “選擇性重傳” + “快速重傳”
    • **3、激進的超時重傳 (Aggressive RTO)——解決尾包延遲問題**
    • 低延遲的本質就是用帶寬換時間
  • 再低延遲也總有意外——KCP 超時淘汰機制
    • KCP 滑動窗口
    • KCP 的超時淘汰機制
  • KCP 應對網絡擁塞的方案——非退讓流量控制
  • 總結

推薦一個零聲教育學習教程,個人覺得老師講得不錯,分享給大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK等技術內容,點擊立即學習: https://github.com/0voice 鏈接。

前言

我是零聲學院的小學徒,我雖然不是計算機科班出身,但我是學數學的,我認為對于一個我不熟悉的東西是需要作知識匯總的,盡量讓自己理解清楚事情的全貌,并且對知識作出恰當的比喻和類比,以達本意。我將仿效上一篇介紹 TCP 協議棧的文章筆法(原文鏈接 在此),詳細的介紹在工程上(尤其是游戲工程)具有廣泛應用的可靠、低延遲的通信協議——KCP.

先運行過去寫過的代碼(與 UDP 協議相關),執行過程使用 Wireshark 去抓包,記錄一路上的 UDP 報文。從現實的 UDP 報文出發,先介紹 UDP 協議棧的簡單簡陋,同時又看到它的低延遲潛力,只要我們在此基礎上,稍做設計,便能設計出可靠的低延遲傳輸協議——KCP。 而后逐步地深入介紹 KCP 協議棧的各個機制的內容,給大家一個對 KCP 的整體性的認知。事不宜遲,我們現在開始。
在這里插入圖片描述

我過去曾寫過一篇文章,它是介紹遠程 DNS 域名查詢服務的,原文鏈接 在此。在那篇文章中,傳輸層是采用 UDP 協議的,讀者可查看那篇文章的代碼,套接字使用數據報模式就是使用 UDP 的開始,

int sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 這是一個通訊方式的參數設定// AF_INET 表示使用 IPv4 的地址協議。// SOCK_DGRAM 表示“數據報套接字”// 0 指代自動選擇與 type 匹配的默認協議。對于 SOCK_DGRAM,默認協議是 UDP(等價于顯式指定 IPPROTO_UDP)。// 返回的整數是一個文件描述符,唯一標識當前創建的套接字。// 后續通過此描述符進行網絡操作:bind():綁定 IP 和端口(服務端)。sendto():發送數據。recvfrom():接收數據。close():關閉套接字。if (sockfd < 0) {   return  -1;    // 這表示通訊狀態設置不成功}

如果讀者要問假如我想使用 TCP 協議怎么辦?那也很簡單,套接字使用數據流模式就 OK 了。

int sockfd = socket(AF_INET, SOCK_STREAM, 0);

回到正題上,我們把使用 UDP 傳輸協議的 DNS 的域名查詢代碼運行一下,利用這個程序去查詢零聲教育的域名

qiming@qiming:~/share/CTASK/TCP_test/DNS_test$ ./dns www.0voice.com
connect : 0
www.0voice.com has address 43.139.121.27Time to live: 0 minutes , 0 seconds
qiming@qiming:~/share/CTASK/TCP_test/DNS_test$

零聲教育的域名是 43.139.121.27。此時,我們早已開啟 Wireshark 來進行網絡抓包了
在這里插入圖片描述
于是找到了相匹配的兩份 UDP 報文
在這里插入圖片描述

我們先從 UDP 協議講起,隨后就會將 KCP 協議。

UDP 協議

我們親眼看到真實的 UDP 報文后,我們再從理論的 UDP 報文來看

0                   1                   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5   <-- 對齊 2 個字節 (16 位)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|    Source Port                |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|    Destination Port           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Length                    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      checksum                 |	<-- UDP 報文的頭部(共 8 個字節)           
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Data Payload (可變長度)    |	<-- 數據荷載,實際數據,對齊值為 2 個字節
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
字段名稱長度(字節)說明
源端口號2發送方端口號,用于標識發送方的應用程序。
目的端口號2接收方端口號,用于標識接收方的應用程序。
長度2UDP報文的總長度,包括UDP頭部和數據部分,以字節為單位。最小值為8字節(僅頭部)。
檢驗和2用于檢測UDP報文在傳輸過程中是否出現錯誤。
數據可變應用層提供的數據,長度可變。

UDP 報文是極其簡單的,沒有復雜的東西。

UDP 的關鍵指標/特性

1、無連接:

  • 核心特性。 發送數據報之前不需要像 TCP 那樣進行“三次握手”建立連接。
  • 意義: 通信開銷極小,延遲非常低(發送第一個數據包前幾乎沒有準備時間)。適用于需要快速響應的場景。

2、不可靠交付:

  • 核心特性。 UDP 協議本身不提供任何機制來保證數據報一定能到達目的地。
  • 具體表現:
    • 不確認 (No Acknowledgement): 發送方發送后不會等待接收方的確認 (ACK)。
    • 不重傳 (No Retransmission): 如果數據報丟失(網絡擁塞、路由器丟棄、校驗失敗等),發送方不會自動重傳。
    • 不保證順序 (No Ordering Guarantee): 后發送的數據報可能比先發送的早到達接收方。UDP 不負責重新排序。
    • 不防止重復 (No Duplication Prevention): 網絡問題可能導致同一個數據報被多次送達接收方(通常由底層 IP 網絡引起)。
  • 意義: 可靠性保證(如果需要)必須由應用程序自己實現(例如,在應用層添加序列號、超時重傳、確認機制),或者應用程序能夠容忍這些情況(如直播丟幾幀畫面)。

3、無擁塞控制:

  • UDP 沒有內置的機制來感知網絡擁塞并調整發送速率。
  • 意義: UDP 發送方會盡可能快地按照應用程序的要求發送數據,無論網絡當前是否擁塞。這可能導致:
    • 加劇擁塞: 在網絡已經擁塞時,UDP 流量會繼續沖擊網絡,可能使情況惡化,影響自身和其他協議(尤其是 TCP)的性能。
    • 公平性問題: 對 TCP 流不公平,因為 TCP 會主動降低速率,而 UDP 不會。
  • 應用程序如果需要在擁塞環境下良好運行,必須自己實現某種形式的速率控制和擁塞感知。

4、無流量控制:

  • UDP 沒有機制讓接收方告訴發送方“慢一點,我處理不過來了”。
  • 意義: 如果發送方發送速度遠快于接收方的處理能力(或接收方應用程序讀取數據的速度),接收方的緩沖區會溢出,導致數據報被丟棄。應用程序需要自行處理速率匹配問題。

5、面向數據報 (Message-Oriented):

  • UDP 每次發送和接收的是一個完整的數據報(報文)。
  • 意義:
    • 保留消息邊界: 應用程序發送多少次 sendto 調用,接收方就需要對應多少次 recvfrom 調用。每個 recvfrom 調用返回一個完整的數據報(或報錯)。數據報之間是獨立的。
    • 與 TCP 的字節流模型形成鮮明對比(TCP 沒有消息邊界,數據是連續的字節流)。

6、頭部開銷小:

  • 固定頭部僅 8 字節,遠小于 TCP 頭部的 20 字節(通常)或更多(帶選項)。
  • 意義: 對于傳輸小數據包的應用(如 DNS 查詢、心跳包),UDP 的協議開銷比例更低,效率更高。

7、支持廣播和多播(對局域網內的所有主機可見):

  • UDP 數據報可以發送到:
    • 單播 (Unicast): 單個目標主機(最常見)。
    • 廣播 (Broadcast): 同一子網內的所有主機(目的 IP 地址為特定子網的廣播地址,如 192.168.1.255)。
    • 多播 (Multicast): 訂閱了特定多播組的一組主機(目的 IP 地址為 D 類地址 224.0.0.0 - 239.255.255.255)。
  • 意義: 這是 TCP 無法做到的(TCP 嚴格是點對點連接)。UDP 是實現如網絡發現、視頻會議、實時數據分發(股票行情)等多播/廣播應用的基石。路由器需要支持 IGMP 等協議來管理多播組成員關系。

UDP vs TCP 關鍵對比

特性UDPTCP
連接無連接面向連接 (三次握手)
可靠性不可靠 (不確認、不重傳、不排序、不保序)可靠 (確認、重傳、排序、保序)
交付保證盡力而為交付 (Best Effort)保證按序、無差錯、不丟失、不重復的交付
流量控制有 (滑動窗口)
擁塞控制有 (多種復雜算法)
數據模型面向數據報 (保留消息邊界)面向字節流 (無消息邊界)
頭部大小小 (8 字節)大 (通常 20 字節 + 選項)
速度/延遲快 (連接建立開銷小,無確認重傳延遲)相對較慢 (連接建立/斷開開銷,確認重傳延遲)
廣播/多播支持不支持 (僅單播)
適用場景實時應用、簡單查詢、多播廣播、容忍丟包Web 瀏覽、文件傳輸、郵件、需要可靠性的應用

UDP 的典型應用場景

1、對延遲敏感,能容忍少量丟失的應用:

  • 實時音視頻流 (VoIP, Video Conferencing, Live Streaming)
  • 在線游戲 (狀態更新、位置同步)
  • 實時金融行情推送

2、簡單查詢/響應,數據量小:

  • DNS (域名解析)
  • DHCP (動態獲取 IP 地址)
  • SNMP (網絡管理)
  • TFTP (簡單文件傳輸)

3、多播和廣播應用:

  • 服務發現 (如 mDNS/Bonjour)
  • 路由協議更新 (如 RIP)
  • 流媒體分發

4、在應用層實現可靠性的場景:

  • 某些自定義協議或基于 UDP 構建的可靠傳輸協議 (如 QUIC - HTTP/3 的基礎, DCCP, 部分 VPN 協議)。

UDP 是一種極其精簡、快速但“不可靠”的傳輸層協議。它的核心價值在于低延遲低開銷,適用于那些對時效性要求極高、能夠容忍一定程度數據丟失或由應用層自行處理可靠性的場景。理解其報文結構(特別是端口號、長度、校驗和的作用)以及無連接、不可靠、無流控/擁控的特性,是正確使用 UDP 或選擇 UDP 還是 TCP 的關鍵。雖然 UDP 本身簡單,但在其之上構建可靠的應用層協議(如 QUIC)是當前網絡協議發展的一個重要方向。

KCP 協議的基礎

我們知道 UDP 的傳輸機制與 TCP 是極其不一樣的,強調 低延遲低開銷,在游戲等領域有著廣泛的應用。那么,如何在 UDP 基礎之上,作些改動,讓其變得更加可靠但依舊低延遲低開銷呢?KCP 協議通信方案!

KCP的全稱是Quick UDP Protocol,即“快速用戶數據報協議”。KCP 協議是一種基于 UDP 的可靠傳輸協議,由國內開發者 skywind3000 設計并開源。它的核心目標是在保證一定可靠性的前提下,盡可能地降低傳輸延遲,特別適合對實時性要求高的網絡應用。

KCP 通過 24 字節精簡頭部 + 雙隊列緩沖管理(發送/接收隊列 + 緩沖區) + 時間戳驅動更新(滑動窗口的超時淘汰機制),在 UDP 上實現了低延遲可靠傳輸。其核心代碼約 1000 行 C 語言(見 GitHub),適合嵌入實時應用(如游戲引擎)。開發者需注意它不是 TCP 的替代品,而是為特定場景優化的傳輸層增強工具。

KCP 的構造

KCP 協議通過自定義報文頭在 UDP 之上構建可靠傳輸,其設計追求簡潔高效和低延遲。以下是 KCP 報文結構、核心字段和代碼實現的關鍵解析:

struct kcp_segment_header {uint32_t conv;     // 會話 ID(虛擬連接標識)uint8_t  cmd;      // 命令類型(見下表)uint8_t  frg;      // 分片編號(0=最后一個分片,>0 表示后續還有分片)uint16_t wnd;      // 接收窗口剩余大小(接收方能接收的數據量)uint32_t ts;       // 時間戳(發送時刻,用于 RTT 計算)uint32_t sn;       // 序列號(當前包的序號)uint32_t una;      // 待確認序號(發送方尚未收到的 ACK 的起始序號)uint32_t len;      // 數據長度(不含頭部的數據部分長度)
};

? 頭部固定 24 字節,后續緊跟用戶數據(若有)。

網絡套接字socket 與 KCP 控制塊相關聯(這與 TCP 一樣,TCP 協議棧維護 TCB,即 TCP 控制塊),它主要是放置 KCP 協議棧的內容(里面當然是包括 “滑動窗口” 的)。

// KCP 會話控制塊(簡化版)
struct ikcpcb {// 連接標識uint32_t conv;// 窗口管理uint32_t snd_una;  // 最早未確認包序號uint32_t snd_nxt;  // 下一個待發包序號uint32_t rcv_nxt;  // 下一個待接收包序號// 隊列管理struct IQUEUEHEAD snd_queue; // 待發送隊列struct IQUEUEHEAD rcv_queue; // 亂序接收隊列struct IQUEUEHEAD snd_buf;   // 已發送等待 ACK 隊列struct IQUEUEHEAD rcv_buf;   // 按序接收隊列// 超時管理uint32_t current;    // 當前時間戳uint32_t rx_rttval;  // RTT 波動值uint32_t rx_srtt;    // 平滑 RTTuint32_t rx_rto;     // 當前 RTO 值// 配置參數uint32_t mtu;        // 最大傳輸單元(默認 1400)uint32_t fastresend; // 快速重傳觸發閾值(默認 2)uint32_t nodelay;    // 是否啟用無延遲模式(0/1)
};

KCP 協議特性

以下是 KCP 協議的關鍵特點和原理:

  • 底層使用 UDP:
    • KCP 本身不處理底層網絡傳輸,它構建在 UDP 之上。這意味著它繼承了 UDP 的無連接、低開銷、無擁塞控制(默認)等特性。
    • 它通過自己的機制在 UDP 之上實現了可靠傳輸。
  • 核心機制:ARQ (自動重傳請求):
    • 和 TCP 一樣,KCP 也使用確認號、超時重傳、序列號等機制來保證數據包的可靠、有序到達。
    • 它實現了自己的滑動窗口來進行流量控制。
  • 追求低延遲的關鍵設計:
    • 更激進的重傳策略: 這是 KCP 降低延遲的核心。
      • 快速重傳: 當檢測到丟包(比如收到 3 個重復的 ACK)時,KCP 會立即重傳丟失的包,而不像標準的 TCP RTO (重傳超時) 那樣需要等待一個較長的超時時間(通常至少 200ms)。KCP 的 RTO 最小值可以設置得非常低(如 10ms 甚至更低)。
      • 選擇性重傳: KCP 可以選擇性地只重傳真正丟失的數據包,而不是像 TCP SACK 出現之前那樣可能需要重傳整個窗口的數據(盡管現代 TCP 也支持 SACK)。
    • 非退讓的流控: KCP 的流量控制算法(窗口大小調整)不像 TCP 那樣對丟包反應“劇烈”。TCP 在發生擁塞(丟包)時會大幅減小擁塞窗口(cwnd),導致傳輸速率驟降。KCP 的窗口調整可以配置得更平滑,減少因單次丟包造成的傳輸速率波動和恢復時間,從而保持更穩定的低延遲。用戶可以根據網絡狀況靈活配置其擁塞控制策略的激進程度。
    • 更小的傳輸單元: KCP 鼓勵更小的數據分片傳輸,有助于降低單個包丟失對整個傳輸的影響。
    • 更快的 ACK: KCP 可以配置為更及時地發送 ACK 確認包,減少發送端等待確認的時間。

性能方面的優點:

  • 顯著降低延遲: 在存在一定丟包和波動的網絡環境下(如移動網絡、跨國網絡),KCP 通常能比 TCP 提供低得多的端到端延遲。
  • 可配置性強: 開發者可以通過調整一系列參數(如 RTO 最小值、快速重傳觸發條件、窗口大小、是否啟用 nodelay 等)來精細控制 KCP 的行為,在延遲、帶寬利用率和抗丟包能力之間進行權衡,以適應不同的應用場景和網絡條件。
  • 用戶態實現: 作為應用層協議,易于集成和調試,不依賴操作系統內核。

性能方面的缺點/代價:

  • 更高的帶寬消耗: 更激進的重傳和更快的 ACK 意味著在網絡狀況不佳時,KCP 會比 TCP 產生更多的冗余數據包(重傳包、ACK包),占用更多帶寬。
  • 可能加劇網絡擁塞: 如果配置過于激進且網絡本身已經擁塞,KCP 的大量重傳可能會進一步惡化網絡狀況(需要合理配置流控和擁塞避免策略)。TCP 的“退讓”特性在維持整個網絡穩定性方面是有價值的。
  • 實現復雜度: 應用開發者需要理解并合理配置 KCP 的參數才能達到最佳效果,這比直接使用 TCP 稍復雜。
  • 可靠性依賴實現: 其可靠性完全依賴于自身的 ARQ 實現,不像 TCP 經過了幾十年的廣泛驗證和優化。

主要應用場景:

  • 實時網絡游戲: 尤其是動作類、MOBA、FPS 等對延遲極其敏感的游戲,是 KCP 最經典的應用領域。手游中使用尤其廣泛。
  • 實時音視頻通話: 如視頻會議、直播連麥等,需要低延遲保證流暢互動。
  • 弱網環境優化: 在移動網絡(4G/5G)、長距離鏈路(跨國)、或質量不穩定的 Wi-Fi 環境下,提升應用的響應速度和流暢性。
  • 需要低延遲的遠程控制/操作: 如云桌面、遠程機器人控制等。
  • 替代 TCP 在某些特定延遲敏感場景的應用。

那么 KCP 與 TCP 有何相同點呢?

KCP 與 TCP 的基礎可靠性機制相同

機制作用KCP & TCP 實現方式
序列號 (Sequence Number)標識數據包順序每個數據包攜帶唯一序列號,接收方按序重組
確認應答 (ACK)告知發送方數據接收狀態接收方發送 ACK 包(含已接收的最大連續序列號)
超時重傳 (RTO)應對丟包未收到 ACK 的包在超時后重傳
滑動窗口 (Sliding Window)流量控制與批量傳輸限制發送方可發送的數據量,通過 ACK 推進窗口釋放空間

? 兩者均通過 序列號 + ACK + 重傳 + 滑動窗口 實現可靠傳輸(本質是 ARQ 自動重傳請求)

KCP 與 TCP 的滑動窗口的核心邏輯相同

概念作用KCP & TCP 一致性
發送窗口 (snd_una)跟蹤最早未確認包窗口左邊界,收到 ACK 后向右移動
接收窗口 (rcv_nxt)期待接收的下一個包序號接收方按序交付數據后向右移動
窗口大小 (snd_wnd/rcv_wnd)控制傳輸速率限制發送速率(避免淹沒接收方)

? 窗口滑動邏輯完全一致:ACK 推動發送窗口,連續數據推動接收窗口。

KCP 與 TCP 的基礎組件相同

組件功能KCP & TCP
重傳計時器檢測丟包超時每個發送包獨立計時,超時觸發重傳
緩沖區管理緩存已發送未確認/亂序到達的數據發送/接收端均維護隊列
校驗和檢測數據損壞可選支持(KCP 依賴下層 UDP 校驗,TCP 強制)

總結:異同本質

維度KCPTCP
基礎結構? 與 TCP 完全相同? 標準滑動窗口
窗口單位? 包數量(非字節)字節數
控制權? 應用層可編程內核固定控制
擁塞控制? 需開發者實現內置完善算法
ACK 機制? 支持無延遲 ACK + 精確重傳信息依賴系統實現和擴展

KCP 的可靠傳輸機制——ARQ

KCP 協議的核心 ARQ(自動重傳請求)策略是 選擇性重傳(Selective Repeat, SR),但在此基礎上進行了深度優化和激進參數調整。其實,這點跟 TCP 沒啥區別。

三種 ARQ 機制對比

ARQ(Automatic Repeat reQuest) 是可靠傳輸協議的核心機制,其三種經典實現方式——停等式(Stop-and-Wait)、回退 N 幀(Go-Back-N) 和選擇性重傳(Selective Repeat)——構成了現代網絡協議(如 TCP、KCP)的基礎。以下是它們的詳細對比及與 KCP/TCP 的關聯:

特性停等式 (Stop-and-Wait)回退 N 幀 (Go-Back-N, GBN)選擇性重傳 (Selective Repeat, SR)
發送窗口大小1 個包N 個包(N>1)N 個包(N>1)
接收窗口大小1 個包1 個包N 個包
重傳策略超時后重發當前包超時后重發所有未確認包僅重傳丟失的包
亂序處理丟棄亂序包丟棄亂序包緩存亂序包
傳輸效率? 最低(每包需單獨確認)?? 中等(批量發送但重傳開銷大)??? 最高(僅重傳丟失包)
帶寬利用率低(RTT 內只能發 1 個包)中(流水線發送,但重傳冗余)高(精準重傳 + 亂序緩存)
典型場景極弱網絡(如衛星鏈路)早期 TCP(如 Tahoe)現代 TCP(SACK)/ KCP

停等式 (Stop-and-Wait) 有點小撈,它太笨了。? 問題:每個包必須等 ACK 到達才能發下一個,效率極低。
在這里插入圖片描述

回退 N 幀 (Go-Back-N, GBN) 處理的批量很大。? 問題:單包丟失導致大量冗余重傳(尤其高延遲網絡)。
在這里插入圖片描述
選擇性重傳 (Selective Repeat, SR) 就具有相當的現代性了。? 優勢:僅重傳丟失包(SN=2),接收方緩存亂序包(3,4,5)。
在這里插入圖片描述

KCP 的選擇性重傳

一、基礎機制:選擇性重傳(SR)

特性KCP 的實現
重傳對象僅重傳真正丟失的包(非整個窗口)
亂序處理接收方緩存亂序到達的包,待缺失包到達后按序提交
確認機制ACK 包攜帶精確的丟包信息(類似 TCP SACK,但為原生支持)
效率優勢單包丟失不影響后續包傳輸,避免回退 N 幀(GBN)的冗余重傳

? 核心邏輯:“誰丟傳誰” —— 通過 ACK 包中的序列號信息精準定位丟失包。

二、KCP 對 SR 的增強策略

1.、激進快速重傳

  • 觸發條件:收到 2 個重復 ACK(默認值,可配置)即重傳(TCP 需 3 個)。
  • 優勢:將丟包檢測時間從 RTT + 超時等待 壓縮至 ≈1 RTT。

2、超時重傳優化

  • RTO 最小值:可設為 5-10ms(TCP 通常 ≥200ms),加速兜底重傳。
  • RTO 計算:啟用 nodelay 模式時,RTO = RTT + 1×RTTVAR(更貼近當前延遲)。

3、ACK 無延遲反饋

  • 機制:啟用 ack_nodelay 時,收到數據包立即回復 ACK(TCP 常延遲 40ms 等待捎帶)。
  • 效果:進一步減少丟包判定時間(尤其對單向數據流)。

4、 窗口淘汰機制

  • 問題場景:最早發送的包(如 SN=10)多次重傳失敗,阻塞窗口滑動。
  • KCP 方案:
    • 若后續包(如 SN=15)被確認 → 強制將窗口左邊界推進到 SN=16。
    • 放棄舊包的重傳,避免傳輸停滯(犧牲少數包可靠性換流動性)。

KCP 的激進重傳策略——低延遲設計!

KCP 的低延遲主要來源于它對 丟包 這一網絡傳輸最大敵人的處理方式。TCP 為了保證網絡的全局公平性和穩定性,對丟包的反應是相對“保守”和“緩慢”的。而 KCP 的設計哲學是:為了應用的實時性,可以更早、更主動、更精準地重傳丟失的數據包,即使這意味著可能消耗更多的帶寬

1、 快速重傳 (Fast Retransmit):跳過漫長的等待

  • 原理: 當接收方發現接收到的數據包序列號不是連續的(即出現“空洞”),它會立即向發送方發送一個 ACK 包,指出它期望接收的下一個序列號(即空洞的開始位置)。如果發送方連續收到 3個(默認值,可配置) 或更多針對同一個數據包的重復 ACK (DupACK),它就立即推斷該數據包很可能丟失了。
  • 與 TCP 的關鍵區別:
    • 觸發閾值更低: TCP 通常也需要 3 個 DupACK 觸發快速重傳(NewReno 及以后算法)。看起來一樣?不!關鍵在于時間窗口。
    • RTO 最小值極低: TCP 的 RTO (Retransmission Timeout) 計算復雜,其最小值通常被限制在 200ms 左右(Linux 默認)。這意味著,即使觸發了快速重傳,TCP 也可能在等待 RTO 超時后才行動,或者其 RTO 本身就很大。KCP 的 RTO 最小值 (minrto) 可以由用戶直接設置,典型值低至 10ms 甚至 5ms。即使沒有 DupACK,KCP 的常規超時重傳等待時間也遠短于 TCP。
    • 反應速度: 當收到足夠的 DupACK 時,KCP 不等待任何定時器超時,立即重傳懷疑丟失的數據包。而 TCP 在收到 DupACK 后,雖然會啟動快速重傳,但可能受到擁塞窗口調整、RTO 計算等因素影響,響應速度不如 KCP 直接和激進。
  • 延遲收益: 在發生單包或少量丟包時,KCP 能在 幾十毫秒內 完成重傳(收到 DupACK -> 立即重發),而 TCP 可能因為 RTO 較大或算法保守需要等待 幾百毫秒。這對于實時應用(如游戲中一個關鍵操作指令丟失)是質的飛躍。

2、選擇性重傳 (Selective Repeat / SACK-like Behavior):精準打擊,避免浪費

  • 原理: 當接收方檢測到多個不連續的數據包丟失時,它需要告知發送方具體是哪些包丟了。KCP 在其 ACK 包中攜帶了接收窗口內所有缺失數據段的起始和結束序列號信息(類似于 TCP 的 SACK 選項,但實現方式不同)。
  • 與 TCP 的關鍵區別:
    • TCP 早期版本 (Reno): 在收到 DupACK 進入快速恢復階段時,如果只丟失一個包,效果尚可。但如果一個窗口內丟失多個包,Reno 在收到部分新數據的 ACK 后就會錯誤地認為所有丟失包都已重傳成功,退出快速恢復,導致剩余丟失包必須等待 RTO 超時(即所謂的“重傳超時”問題),造成巨大的延遲(幾百毫秒到幾秒)。
    • TCP 現代版本 (SACK): 通過 SACK 選項也能實現選擇性確認,解決了 Reno 的多個丟包問題。KCP 與 TCP SACK 在“選擇性”理念上相似,但 KCP 的實現通常更輕量和直接,并且其整體重傳策略(結合極低的 RTO 和快速響應)更為激進。
  • 延遲收益: 在發生多個數據包連續丟失的情況下,KCP 能通過接收方精確的反饋,一次性重傳所有已知丟失的包,避免了像 TCP Reno 那樣因多次 RTO 超時或等待導致的累積延遲。即使對比 TCP SACK,KCP 更快的觸發和重傳動作也能進一步壓縮恢復時間。

低延遲 ACK 機制能綜合實現 “選擇性重傳” + “快速重傳”

想象一個場景:在我們中學時代,監考老師給我們點名,他們會一個一個地點,點一個學生就喊一句 “到”,當點到下一位,無任何人應答的時候,老師立馬就把這個學生記到遲到缺席的 “黑名單” 里,并通知班主任叫他趕快來,在此期間一直等他,直到老師不耐煩了,把它記作缺考(超時淘汰)。這其實就是一個低延遲 ACK 。

以下這個圖示正是一個低延遲 ACK 的工作原理展示。

時間線 (向下流動)        發送方 (Sender)                    接收方 (Receiver)                    事件說明
-------------------    ---------------------------    ---------------------------    --------------------------------|                 發送 Seq1                    ->                            ||                 發送 Seq2                    ->                            ||                 發送 Seq3 (丟失)              -> (丟失)                    **Seq3 在網絡中丟失**|                 發送 Seq4                    ->                            ||                 發送 Seq5                    ->                            ||                                            <-         ACK1 (確認Seq1)     **低延遲 ACK!**|                                            <-         ACK2 (確認Seq2)     **低延遲 ACK!**|                                            <-         ACK2 (重復ACK)       **收到 Seq4 (亂序),立即重復 ACK2 索要 Seq3**|                                            <-         ACK2 (重復ACK)       **收到 Seq5 (亂序),立即重復 ACK2 索要 Seq3**|                                                                          **發送方收到第2個重復ACK(2) (假設fastresend=2)**|                 重傳 Seq3                   ->                            **快速重傳觸發! (只重傳丟失的Seq3)**|                                            <-         ACK3 (確認Seq3)      **低延遲 ACK! Seq3到達**|                                                                          **接收方已緩存 Seq4, Seq5,現在可交付 Seq3, Seq4, Seq5**|                                            <-         ACK5 (確認Seq5)      **累積確認/選擇性ACK (確認Seq3,4,5)**|                 發送 Seq6                   ->                            | 繼續發送新數據|                                            <-         ACK6 (確認Seq6)      ||                  ...                        ...                           ...

當 KCP 收到一個數據包時,它不會等待interval定時器到期或等待有數據要回傳時捎帶 ACK,而是立即生成一個 ACK 包發送回去。

更及時的 ACK 反饋:減少發送端的等待

  • 原理: KCP 提供了靈活的 ACK 發送策略:
    • ack_nodelay: 啟用后(推薦),當 KCP 收到一個數據包時,它不會等待interval定時器到期或等待有數據要回傳時捎帶 ACK,而是立即生成一個 ACK 包發送回去。
    • 禁用時,會嘗試稍作等待(interval內)以便捎帶數據或合并 ACK。
  • 與 TCP 的關鍵區別: TCP 通常采用捎帶確認策略,即接收方在發送數據時,才把 ACK 信息放在回傳數據包的首部中一起發回。如果沒有數據要回傳,TCP 會設置一個小的延遲定時器(通常幾十毫秒)等待,希望有數據可以捎帶。如果沒有,才單獨發送一個純 ACK 包。這個延遲是為了減少純 ACK 包的數量。
  • 延遲收益: 啟用 ack_nodelay 后,發送方能更快地知道數據包是否成功到達。這帶來兩個好處:
    • 加速快速重傳觸發: 丟失包的 DupACK 能更快地返回到發送方。
    • 推進發送窗口: 確認包能更快地釋放發送窗口的空間,允許發送方發送后續的新數據,提高吞吐量和降低整體傳輸完成時間。
    • 代價:可能增加少量純 ACK 包的帶寬消耗。

3、激進的超時重傳 (Aggressive RTO)——解決尾包延遲問題

  • 原理: KCP 使用自己獨立的 RTO 計算算法(基于 RTT 測量和變化)。雖然算法本身與 TCP 的 Karn/Partridge 算法類似,但其核心參數可由用戶精細控制:
    • minrto: 允許設置的最小 RTO 值(如 10ms)。TCP 通常有系統級下限(200ms)。
    • nodelay: 啟用后(通常推薦啟用),會顯著改變 RTO 計算方式:
      • 第一次 RTO 計算:RTO = RTT + max(clock_drift, 4 * RTTVAR)
      • 后續 RTO 計算:RTO = RTT + 1 * RTTVAR (非常接近最新的 RTT 測量值)
    • interval: KCP 內部輪詢間隔(如 10ms)。這決定了它檢查超時的頻率。
  • 與 TCP 的關鍵區別:
    • 用戶可配置性: 開發者可以根據網絡環境和應用需求,將 minrto 設置得非常低(如 10ms),而 TCP 的內核參數調整通常受限且影響全局。
    • 更快的檢測: 更小的 interval 和 minrto 意味著 KCP 能更快地檢測到超時(可能沒有觸發快速重傳的丟包,如尾包丟失)。
    • 更激進的增長: nodelay 模式下的 RTO 計算比標準 TCP 更激進,增長幅度小,使得超時重傳的等待時間更接近最新的 RTT 測量值,而不是像 TCP 那樣指數級退避導致 RTO 迅速膨脹到秒級。
  • 延遲收益: 對于那些無法觸發快速重傳(如只丟失一個包且后面沒有新數據,無法產生 DupACK)的丟包場景,KCP 能在 10ms - 幾十ms 級別 的超時后立即重傳,而 TCP 至少需要等待 200ms 以上。這解決了“尾包延遲”問題。

協同效應:如何合力實現低延遲

  • 丟包檢測快: 通過 ack_nodelay 和精確的序列號/ACK機制,接收方能快速發現丟包并通知發送方 (DupACK)。
  • 決策快: 收到足夠 DupACK (閾值可配,默認3) 后,KCP 立即決策重傳,不等待定時器。
  • 重傳動作快: 利用選擇性重傳信息,只重傳丟失的包。
  • 兜底快: 即使沒有觸發快速重傳(如尾包丟失),極低的 minrto 和快速的內部輪詢 (interval) 也能保證在極短時間(如 10-30ms)后通過超時重傳補發。
  • 恢復快: 一旦丟失的包被重傳并確認,發送窗口能迅速前進(因為 ACK 回來得也快 - ack_nodelay),后續數據流能很快跟上,避免了 TCP 因 RTO 膨脹和窗口驟減導致的傳輸速率“雪崩”和緩慢恢復。

低延遲的本質就是用帶寬換時間

KCP 激進重傳策略的核心思想是:不惜以可能增加帶寬消耗(發送更多重傳包和更及時的純 ACK 包)和潛在加劇網絡擁塞為代價,換取傳輸延遲的極大降低。 它通過一系列精心設計的、高度可配置的機制,將網絡傳輸中最耗時的環節——丟包檢測、決策、重傳和恢復——的時間壓縮到了極致(毫秒級),從而滿足了實時應用對低延遲的苛刻要求。這種“帶寬換時間”的權衡在實時游戲、音視頻通信等場景下通常是值得的,因為用戶體驗對延遲的敏感度遠高于對少量額外帶寬消耗的敏感度。

再低延遲也總有意外——KCP 超時淘汰機制

我們先設想一個情景:當我們在玩英雄聯盟的時候,如果我們的電腦卡頓(ping 值很高),英雄在漂移,情況持續了 3 min,網絡恢復正常之后,系統并沒有把我們電腦卡頓過程時候,別的英雄擊殺我們的片段給出,而是快速跳過,最后只顯示我們在泉水之中。這,就是 KCP 超時淘汰機制,極其具有實用性和工程性。

KCP 滑動窗口

KCP 超時淘汰機制是從屬于 KCP 滑動窗口的管理機制的,其結構圖示如下

發送方 (Sender)                                                  接收方 (Receiver)
+---------------------------------------------------+         +---------------------------------------------------+
|                **發送緩沖區 (Send Buffer)**        |         |                **接收緩沖區 (Recv Buffer)**        |
| +-----------------------------------------------+ |         | +-----------------------------------------------+ |
| | 已發送 **已確認** (Delivered & Acked)          | |         | | 已接收 **已交付應用** (Delivered to App)        | |
| | [SND.UNA 之前的數據]                           | |         | | [RCV.NXT 之前的數據]                           | |
| |                                               | |         | |                                               | |
| +-----------------------------------------------+ |         | +-----------------------------------------------+ |
| | 已發送 **未確認** (In Flight / Outstanding)     | |  ---->  | | 已接收 **待交付** (Received, Not Delivered)   | |
| | [**發送窗口 (Sending Window)** 的核心區域]      | | 數據包   | | [**接收窗口 (Receiving Window)** 可用空間前部]| |
| | * SND.UNA (發送未確認起點)                      | |  ---->  | | * RCV.NXT (期望接收起點)                      | |
| | * SND.NXT (下一個發送位置) -->                  | |         | |                                               | |
| |                                                | |         | |                                               | |
| +-----------------------------------------------+ |         | +-----------------------------------------------+ |
| | **允許發送但尚未發送** (Sendable)                | |         | | **可用接收空間** (Available Space)            | |
| | [發送窗口內,SND.NXT 之后的部分]                 | |         | | [**接收窗口 (Receiving Window)** 核心]        | |
| | * 發送窗口右邊界 = SND.UNA + Win                | |         | | * 窗口大小 = RCV.WND                         | |
| |   Win = min(擁塞窗口 cwnd, 接收方通告窗口 rwnd)  | |         | | * 右邊界 = RCV.NXT + RCV.WND                 | |
| +-----------------------------------------------+ |         | +-----------------------------------------------+ |
| | **不允許發送** (Not Sendable)                  | |         | | **不可用空間** (Not Available)               | |
| | [超出當前發送窗口]                              | |         | | [超出當前接收窗口]                           | |
| +-----------------------------------------------+ |         | +-----------------------------------------------+ |
+---------------------------------------------------+         +---------------------------------------------------+

1、發送窗口 (SND_WND) 的約束:

  • KCP 發送端維護一個發送窗口,它定義了當前允許發送的最大數據范圍(從 snd_una 到 snd_una + snd_wnd)。
  • snd_una 指向最早一個尚未被確認(Acknowledged)的數據包的序列號。它是窗口的左邊界。
  • 只有序列號落在 [snd_una, snd_una + snd_wnd) 范圍內的數據包才允許被發送(包括首次發送和重傳)。

2、窗口的推進 (Advancing):

  • 當接收方 ACK 了 snd_una 指向的包(以及按序到達的后續包)時,snd_una 就會向右移動(增大),發送窗口也隨之整體向右滑動。
  • 新“暴露”出來的窗口空間允許發送新的數據包。

3、“丟包太久不重發”的本質:窗口淘汰

  • 關鍵決策點: 為了不讓整個傳輸流程被這些頑固的舊丟包卡死(阻塞新數據的發送),KCP 會執行一個策略:強制將 snd_una 推進到接收方已 ACK 的最小連續序列號之后的位置。

KCP 的超時淘汰機制

我接下來通過圖示簡單介紹一下超時淘汰機制。

圖 1:初始狀態(正常傳輸)

發送窗口范圍: [10, 11, 12, 13, 14, 15]  (snd_una=10, snd_wnd=6)
已發送未確認: █  █  █  █  █  █ 10  11 12 13 14 15  <-- 序列號
狀態:所有包已發送,等待 ACK。

圖 2:發生丟包(包 10,11,12 丟失)——選擇性重傳

發送窗口范圍: [10, 11, 12, 13, 14, 15]  
已發送未確認: ?  ?   ?  █   █   █ 10 11  12 13  14  15
狀態:-13,14,15 被接收方收到,但無法 ACK(因包 10 未到,不連續)-10,11,12 超時重傳多次(🔥)仍失敗。

圖 3:觸發淘汰機制(強制推進窗口)

接收方反饋:ACK 13,14,15(非連續確認)
KCP 決策:放棄包 10,11,12(重傳失敗)!新窗口范圍: [16, 17, 18, 19, 20, 21]  (snd_una=16, snd_wnd=6)
已發送未確認: █  █  █  █  █  █ 16 17 18 19  20 21
淘汰影響:-10,11,12 被移出窗口 ?(不再重傳)- 新數據包 16-21 立即發送 ?

圖 4:新丟包處理(包 17 丟失)

窗口范圍: [16, 17, 18, 19, 20, 21]  
已發送未確認: █  ?  █  █  █  █ 16 17 18 19  20 21
狀態:-17 丟失 → 觸發 **快速重傳**(仍在窗口內)-18,19,20,21 正常傳輸。

關鍵決策點: 為了不讓整個傳輸流程被這些頑固的舊丟包卡死(阻塞新數據的發送),KCP 會執行一個策略:強制將 snd_una 推進到接收方已 ACK 的最小連續序列號之后的位置。在本案例中:
1、當前 snd_una = 10。
2、包 10, 11, 12 丟失且重傳多次失敗。
3、接收方收到了包 13, 14, 15 并 ACK 了它們(但無法 ACK 10, 11, 12)。
3、KCP 發現 13, 14, 15 被 ACK 了,但 10 這個關鍵點一直沒 ACK。
4、KCP 判定 10, 11, 12 重傳無望,決定將 snd_una 直接推進到 16(假設 15 是當前收到的最大連續包)。
后果:
5、序列號 10, 11, 12 的包被移出發送窗口 ([snd_una=16, snd_una+snd_wnd)) 的范圍。
6、這些包不再有資格被重傳,因為 KCP 的重傳隊列只維護窗口內的包。
7、發送窗口騰出了大量空間,新的數據包(序列號 >=16)可以立即被發送,傳輸得以繼續。

與 TCP 的核心差異

機制KCPTCP
窗口淘汰? 主動放棄超時舊包,推進窗口? 堅持重傳直到成功或斷開
阻塞避免? 新數據不受舊丟包影響🐢 舊丟包阻塞整個窗口
適用場景實時應用(容忍部分丟包) 高可靠性傳輸(如文件下載)

KCP 應對網絡擁塞的方案——非退讓流量控制

讓我們用一個“高速公路應急車道管理”的比喻,來形象地理解 KCP 的非退讓流量控制的必要性,并將其與傳統 TCP 的退讓式(AIMD) 控制進行對比。

場景設定

  • 道路: 一條繁忙的高速公路,有 常規車道 和 應急車道。
  • 車輛: 代表需要傳輸的數據包。
  • 交通狀況: 代表網絡狀況。偶爾有小事故(輕微丟包),也可能有大擁堵(嚴重擁塞)。
  • 交通管理中心 (TCP): 遵循嚴格的安全規則。一旦監測到任何事故(丟包),就認為可能發生大擁堵(嚴重擁塞),立即采取激進措施。
  • 特種物流車隊 (KCP): 運輸的是高時效性、高優先級的物資(如救援物資、緊急醫療用品)。它們的核心任務是盡最大可能、以最快速度、穩定地將物資送達,即使路況不完美。它們擁有特殊的通行策略。

傳統 TCP (退讓式/AIMD,擁塞控制配合慢啟動) 的比喻

  • 策略 (“寧可錯殺,不可放過”):
    • 只要高速攝像頭(丟包檢測)拍到任何一起小剮蹭事故(一個丟包),交通管理中心 (TCP) 就立刻、武斷地認定整條高速即將癱瘓(嚴重擁塞)。
    • 行動:
      • 立即關閉一半常規車道! (乘性減 - 擁塞窗口減半)。所有車輛(數據包)瞬間只能使用一半的道路資源。
      • 然后極其緩慢地、一條一條地重新開放車道。 (加性增 - 擁塞窗口緩慢線性增長)。需要很長時間才能恢復到原來的通行能力。
  • 后果:
    • 交通能力瞬間腰斬: 即使事故很小且很快處理完,車流(吞吐量)也暴跌。大量無辜車輛被堵在路上。
    • 恢復極其緩慢: 重新開放車道的過程非常保守和緩慢,整體運輸效率低下。
    • 對高時效物資是災難: 特種物流車隊 (重要數據) 即使沒有卷入事故,也被迫降速、延誤,無法完成緊急任務。
  • 必要性 (在公共道路上): 對于普通交通,這種策略是必要的,以防止自私的司機(應用)過度占用道路導致全局崩潰(擁塞崩潰)。安全第一,公平性優先。

KCP (非退讓流控) 的比喻

  • 策略 (“精準處置,保持運力”):

    • 特種車隊有自己的指揮中心 (KCP協議棧)。
    • 當車隊收到報告,某輛特定運輸車(一個數據包,如 Seq102)在某個路段發生了小事故(丟失)。
    • 行動:
      • 立即派遣一輛備用車 (快速重傳) 走應急車道 (選擇性重傳) 去替換那輛故障車。目標:最快速度補上缺失的物資。
      • 絕不關閉主車道! (非退讓 - 發送窗口 snd_wnd 不縮減)。其他所有運輸車(后續數據包)繼續在主車道 (常規車道) 上按計劃行駛,只要目的地倉庫 (接收方) 還有空間 (rcv_wnd)。
      • 可能微調車速 (調整 interval/RTO): 指揮中心可能會命令整個車隊稍微降低一點車速(比如從 120km/h 降到 100km/h),給處理事故留出更多余量,避免連續出事。但這只是調速,不是封路!
      • 利用一切可用空間: 一旦目的地倉庫報告有更多空位(通告更大的 rcv_wnd),指揮中心立刻允許派出更多運輸車(增大 snd_wnd),填滿所有可用車道。
  • 后果:

    • 運力影響最小化: 只有出事的那一輛車需要替換,其他車輛幾乎不受影響。整體運輸量(吞吐量)保持高位且穩定。
    • 時效性最大化: 高優先級物資總能盡快利用可用道路資源送達。平均延遲低,延遲波動小。
    • 快速恢復潛力: 一旦備用車抵達(重傳成功)或路況變好,車隊可以瞬間提速或加車(利用更大的 snd_wnd),恢復到甚至超過之前的運力。

必要性 (對特種車隊):

  • 任務優先: 對于救援物資、緊急醫療用品(實時音視頻、游戲指令、金融交易),送達的時效性和穩定性是最高優先級。一次大的延誤或吞吐量暴跌可能導致任務失敗(通話卡頓、游戲卡死、交易超時)。
  • 容忍小事故: 這些小事故(少量丟包)在任務背景下是可以接受的代價(音頻偶爾沙沙聲、畫面小馬賽克),只要主體物資(大部分數據包)能持續、快速、穩定地送達。
  • 專用/可控道路: 特種車隊通常在有優先權、路況相對可控的路線上行駛(如專線、VPN、P2P內網),或者其流量占比不高。它們不會(或不應該)主動去擠垮公共道路(公網核心)。在這種場景下,“自私”一點,優先保障自己的關鍵任務,是必要且合理的。
  • 避免過度反應: 關閉一半車道(窗口減半)對于處理一個小事故是災難性的過度反應,完全違背了特種車隊的核心使命。

以下是非退讓流量控制的程序執行圖例(大家要結合低延遲 ACK 去理解),當出現丟包的時候,稍微降低傳輸速度(RTO 稍微增大,但窗口沒有像 TCP 那樣大幅縮減),當接收方告知緩沖區充足的時候,發送方增大發送窗口的大小。

時間線 (向下流動)    發送方 (Sender)                                        接收方 (Receiver) / 網絡事件
------------------  ----------------------------------------------        ------------------------------------------------|          **狀態:**|          `snd_una = 100` (下一個期望ACK是100)|          `rcv_wnd (來自接收方) = 10` (最新通告)|          `snd_wnd = min(rcv_wnd, max) = 10`|          **發送窗口: [100, 110)**|          **發送: Seq100, Seq101, Seq102, Seq103, Seq104** ->      **網絡正常**|          **發送窗口內剩余: 5 slots (105-109)**|          **發送: Seq105, Seq106, Seq107** ->                     **網絡正常**|          **發送窗口內剩余: 2 slots (108-109)**|                                                                **Seq102 丟失! (網絡擁塞開始)**|                                                                **接收方收到:**|                                                                Seq100 -> **立即發送 ACK(101)** (確認100)|                                                                Seq101 -> **立即發送 ACK(102)** (確認101)|                                                                Seq103 (亂序!) -> **立即發送 ACK(102)** (DUP-ACK, 索要102)|                                                                Seq104 (亂序!) -> **立即發送 ACK(102)** (DUP-ACK)|          <- **收到 ACK(101)** (`snd_una` 推進到101)              |             **發送窗口變為: [101, 111)**|             **發送: Seq108, Seq109** -> (用完當前窗口)            **Seq108, Seq109 可能到達或丟失**|          <- **收到 ACK(102)** (`snd_una` 推進到102)              |             **發送窗口變為: [102, 112)**|             **無新數據,或應用層暫無數據**|          <- **收到 ACK(102) (DUP-ACK 1)**                      **接收方處理Seq105, Seq106...**|          <- **收到 ACK(102) (DUP-ACK 2) [假設fastresend=2]**   **觸發快速重傳條件!**|          **!! 關鍵點 !!** |          **檢測到 Seq102 丟失 (通過 DUP-ACKs)**|          **但 `snd_wnd` 保持不變 = 10 (非退讓!)**|          **動作: 立即重傳 Seq102** ->                          **重傳Seq102到達**|          **可能動作: 輕微增加 RTO 或 減小 `interval` (稍慢發送新數據)**|                                                                **接收方收到 Seq102:**|                                                                **立即發送 ACK(108)** (確認102-107? 或累積ACK)|                                                                **(同時,應用層消費數據,假設釋放了空間)**|                                                                **接收方 `rcv_wnd` 增大 (e.g., =15)**|          <- **收到 ACK(108)** (`snd_una` 推進到108)             |             **發送窗口變為: [108, 118)** (因為 `snd_wnd` 仍為10)|          <- **收到新通告 `rcv_wnd = 15`**                       |          **!! 關鍵點 !!** |          **更新 `snd_wnd = min(15, max) = 15`** (窗口**擴大**!)|          **發送窗口變為: [108, 123)** (立刻獲得更大發送潛力)|          **發送: Seq110, Seq111, ... (直到填滿新窗口)** ->       **網絡擁塞可能緩解或持續...**|          **... 繼續 ...**

總結

KCP 的各項機制之間是有相當大的重合,但歸根結底,其底層運作機理是

  1. 低延遲 ACK :有快速重傳、選擇性重傳的效果,即可靠的 UDP 傳輸。
  2. 超時重傳機制:第一個計時器(在滑動窗口上的設置)是對低延遲 ACK 的補充,解決尾包延遲問題。
  3. 滑動窗口:有選擇性重傳的功效,有序的流量控制。
  4. 非退讓流量控制:這是滑動窗口上的設置。容忍小錯誤、瑕疵,以換取傳輸流暢與穩定,用戶體驗更好
  5. 超時淘汰機制:第二個計時器(在滑動窗口上的設置),是對嚴重超時的包的斷舍離處理。

我還會寫幾篇文章去介紹 KCP 協議的 C/C++ 代碼實現。畢竟如果只有課本理論,那么會很單調的。話又說回來,源代碼是有 1000 多行的,加上雜七雜八的應用,代碼可能直逼 2000 行。故而深入解析 KCP 協議代碼是一個長期的工程,我會繼續跟進,但是近期不會寫,我要花更多的事件去理解這些代碼,而后給大家去講述。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/88938.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/88938.shtml
英文地址,請注明出處:http://en.pswp.cn/web/88938.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

量子計算新突破!阿里“太章3.0”實現512量子比特模擬(2025中國量子算力巔峰)

??摘要??2025年量子計算競爭進入??實用化臨界點??&#xff0c;阿里達摩院發布“太章3.0”量子模擬器&#xff0c;在全球首次實現??512量子比特全振幅模擬??&#xff0c;較谷歌Sycamore的53比特提升近10倍算力維度。本文深度解析三大技術突破&#xff1a;??張量網…

DOM事件綁定時機:解決腳本提前加載導致的綁定失敗

引言&#xff1a;一個讓無數新手抓狂的常見錯誤在JavaScript開發中&#xff0c;尤其是在前端領域&#xff0c;有一個讓無數新手抓狂的問題&#xff1a;明明寫了事件監聽代碼&#xff0c;點擊按鈕卻沒有任何反應&#xff01;更令人困惑的是&#xff0c;代碼邏輯看起來完全正確&a…

游戲框架筆記

游戲的數據有哪些類型無非是只讀數據&#xff08;各種道具配表里的數據&#xff09;和可讀可寫數據&#xff08;玩家屬性、擁有的物品&#xff09;。游戲框架需要哪些管理器用戶數據管理器負責找到數據持久化文件&#xff0c;從中讀取指定用戶的數據&#xff0c;包括玩家的設置…

【C語言進階】指針面試題詳解(2)

上一期內容&#xff0c;大多數的解題思路寫在代碼中&#xff0c;沒有寫在正文中&#xff0c;這就導致系統判斷文章質量不高&#xff0c;沒有什么數據&#xff0c;這一期將思路寫在正文中。注意&#xff1a;運行環境是x86 1.題目1思路&#xff1a;&a是取到了整個數組的地址&…

一文讀懂現代卷積神經網絡—稠密連接網絡(DenseNet)

目錄 什么是 DenseNet&#xff1f; 稠密塊&#xff08;Dense Block&#xff09;詳解 一、稠密塊的核心思想 二、稠密塊的結構組成 1. 卷積單元&#xff08;的結構&#xff09; 2. 密集連接的具體方式 3. 關鍵參數&#xff1a;增長率&#xff08;Growth Rate, k&#xff0…

關于僵尸進程

深入理解僵尸進程&#xff1a;成因、危害與解決方案 進程終止的條件 我們先了解一下進程銷毀的條件&#xff1a; 調用了exit函數在main函數中執行了return語句 無論采用哪種方式&#xff0c;都會有一個返回值&#xff0c;這個返回值由操作系統傳遞給該進程的父進程。操作系統不…

深入解析進程、線程與協程:現代并發編程的三大支柱

深入解析進程、線程與協程&#xff1a;現代并發編程的三大支柱在計算資源日益豐富的時代&#xff0c;理解并發執行機制已成為每位開發者的必修課。本文將帶你深入探索操作系統中的三大并發模型&#xff1a;進程、線程與協程&#xff0c;揭開它們的神秘面紗。引言&#xff1a;并…

奇安信下一代防火墻SecGate3600

一、實驗拓撲&#xff1a;二、實驗目的&#xff08;1&#xff09;讓內網可以訪問外網。&#xff08;2&#xff09;讓外網能夠訪問dmz區域的web服務器。&#xff08;3&#xff09;測試防火墻的防毒功能&#xff0c;并進行檢測。三、實驗步驟&#xff08;1&#xff09;防火墻配置…

基于STM32的智能抽水灌溉系統設計(藍牙版)

????大家好&#xff0c;這里是5132單片機畢設設計項目分享&#xff0c;今天給大家分享的是基于《基于STM32的智能抽水灌溉系統設計》。 目錄 1、系統功能 2.1、硬件清單 2.2、功能介紹 2.3、控制模式 2、演示視頻和實物 3、系統設計框圖 4、軟件設計流程圖 5、原理…

CISSP知識點匯總- 通信與網絡安全

CISSP知識點匯總 域1---安全與風險管理域2---資產安全域3---安全工程域4---通信與網絡安全域5---訪問控制域6---安全評估與測試域7---安全運營域8---應用安全開發一、安全網絡架構和保護網絡組件 1、OSI 7層協議模型 應用層:SMTP、HTTP、SNMP 、TELNET、 FTP、SFTP、POP3、IM…

C++怎么將可變參數傳遞給第三方可變參數接口

文章目錄&#x1f527; 1. 使用 va_list 轉發&#xff08;兼容C/C的傳統方案&#xff09;?? 2. 模板參數包轉發&#xff08;C11 類型安全方案&#xff09;&#x1f9e9; 3. 替代方案&#xff1a;參數封裝與適配**方案A&#xff1a;使用 std::initializer_list (同類型參數)**…

服務端實現阿里云OSS直傳

介紹 阿里云上傳 OSS 有兩種方式&#xff0c;一種是普通上傳&#xff0c;一種是客戶端直傳。 普通上傳&#xff0c;就是需要先將文件上傳到服務端&#xff0c;然后調用接口將文件上傳到阿里云。 當然這種方案經常出現不合理的使用方式&#xff0c;即客戶端充當服務端的角色&…

on-policy和offpolicy算法

一句話總結On-policy&#xff08;同策略&#xff09;&#xff1a;邊學邊用&#xff0c;用當前策略生成的數據更新當前策略。例子&#xff1a;演員自己演完一場戲后&#xff0c;根據觀眾反饋改進演技。Off-policy&#xff08;異策略&#xff09;&#xff1a;學用分離&#xff0c…

CA-IS3082W 隔離485 收發器芯片可能存在硬件BUG

RT&#xff0c;這個RS485 隔離收發器芯片基本上不可用。本來要買CA-IS3082WX&#xff0c;不小心在某寶買到了沒有X 的CA-IS3082W。立創上說沒有X 的版本已經停產&#xff0c;連對應的數據手冊都找不到&#xff0c;全換成WX 了。 這類半雙工485 收發器芯片電路一般都直接把DE 和…

dockerfile 筆記

# 設置JAVA版本 FROM openjdk:20-ea-17-jdk MAINTAINER aaa # 指定存儲卷, 任何向/tmp寫入的信息都不會記錄到容器存儲層 VOLUME /tmp # 拷貝運行JAR包 ARG JAR_FILE COPY app.jar /app.jar RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime RUN echo "Asia/…

高德開放平臺攜手阿里云,面向開發者推出地圖服務產品MCP Server

高德開放平臺攜手阿里云&#xff0c;面向開發者推出地圖服務產品MCP Server&#xff0c;通過技術能力與生態資源的深度協同&#xff0c;助力開發者高效構建標準化地圖服務&#xff0c;加速智能化場景落地。 高德開放平臺攜手阿里云&#xff0c;面向開發者推出MCP Server技術融合…

【論文閱讀】AdaptThink: Reasoning Models Can Learn When to Think

AdaptThink: Reasoning Models Can Learn When to Think3 Motivation3.1 理論基礎3.2 NoThinking在簡單問題中的優勢3.3 動機總結4. AdaptThink4.1 約束優化目標數學建模基本定義原始優化問題懲罰項轉換歸一化處理策略梯度實現優勢函數定義PPO風格損失函數4.2 重要性采樣策略問…

Redis高可用集群一主從復制概述

一、環境概述在分布式集群系統中為了解決服務單點故障問題&#xff0c;通常會把數據復制出多個副本部署到不同的機器中&#xff0c;滿足故障恢復和負載均衡等需求。Redis也是如此&#xff0c;它為我們提供了復制功能&#xff0c;實現了相同數據的多個Redis副本。復制功能是高可…

Java 樹形結構、層級結構數據構建

目錄前言一、樹狀結構數據庫存儲二、工具類三、測試四、自定義樹節點返回類型&#xff08;只保留部分字段&#xff09;1. 新增 TreeNodeDTO 類2.修改TreeUtil 類3.測試4.輸出前言 有時候&#xff0c;開發過程中我們會遇到一些樹狀層級結構。 比如&#xff0c;公司部門組織架構…

求解線性規劃模型最優解

歸納編程學習的感悟&#xff0c; 記錄奮斗路上的點滴&#xff0c; 希望能幫到一樣刻苦的你&#xff01; 如有不足歡迎指正&#xff01; 共同學習交流&#xff01; &#x1f30e;歡迎各位→點贊 &#x1f44d; 收藏? 留言?&#x1f4dd; 既然選擇了遠方&#xff0c;當不負青春…