KCP協定淺析

2023-03-21 21:01:27

概述

KCP協定結合了TCP和UDP協定的特點,是一個快速可靠的協定。
引述官方介紹:

KCP是一個快速可靠協定,能以比 TCP浪費10%-20%的頻寬的代價,換取平均延遲降低 30%-40%,且最大延遲降低三倍的傳輸效果。純演演算法實現,並不負責底層協定(如UDP)的收發,需要使用者自己定義下層資料的傳送方式,以 callback的方式提供給 KCP。連時鐘都需要外部傳遞進來,內部不會有任何一次系統呼叫。
TCP是為流量設計的(每秒內可以傳輸多少KB的資料),講究的是充分利用頻寬。而 KCP是為流速設計的(單個資料從一端傳送到一端需要多少時間),以10%-20%頻寬浪費的代價換取了比 TCP快30%-40%的傳輸速度。

傳統的TCP/UDP協定見參考連結。

協定格式

| 4bit conv | 1bit cmd | 1bit frg | 2bit wnd |
| 4bit ts | 4bit sn |
| 4bit una | 4bit len |
| anybit 資料 |

  • conv:對談序號,通訊雙方一致
  • cmd:報文型別
    • IKCP_CMD_ACK 確認
    • IKCP_CMD_PUSH 資料推播
    • IKCP_CMD_WASK 接收視窗查詢大小
    • IKCP_CMD_WINS 接收視窗大小告知
  • wnd: 己方可用接收視窗大小,接收視窗大小 - 接收佇列大小
  • frg:包分片(數量)
  • sn: 包分片序號
  • ts: 時間戳,用於計算RTO和RTT
  • una:待接收的序列號(確認號),表示該序列號之前的所有報文都收到了,可以刪除
  • len:使用者資料長度
  • 資料:使用者資料

特點

RTO不翻倍

RTO(Retransmission-TimeOut)即重傳超時時間,TCP和KCP是基於ARQ協定實現的可靠性,但TCP的超時計算是RTO2,而KCP的超時計算是RTO1.5,也就是說假如連續丟包3次,TCP是RTO8,而KCP則是RTO3.375,意味著可以更快地重新傳輸資料。

選擇性重傳

tcp 丟包時會全部重傳從該包開始以後的資料,而 kcp 選擇性重傳,只重傳真正丟失的封包。

快速重傳

收到fastresend(設定)個失序報文後,不等待超時,直接重傳,減少丟包等待時間。
而TCP重傳模式:

  • 超時重傳:超過規定的時間 RTO 則重傳
  • 快速重傳:收到三個冗餘ACK,不去等待 RTO ,直接重傳

與TCP相同,都是通過累計確認實現的,傳送端傳送了1,2,3,4,5幾個包,然後收到遠端的ACK:1,3,4,5,當收到ACK = 3時,KCP知道2被跳過1次,收到ACK = 4時,知道2被跳過了2次,此時可以認為2號丟失,不用等超時,直接重傳2號包,大大改善了丟包時的傳輸速度。

非延遲 ACK

停等ARQ協定

  • A會為每個即將傳送的資料編號,編號的目的是為了標識資料和給資料排序
  • A傳送完資料之後,會給這次傳送的資料設定一個超時計時器
  • B收到資料,將會返回一個確認,該確認也有自己的編號
  • A收到確認,將刪除副本且取消超時計時器,保留副本的原因是傳輸可能出錯
  • B收到錯誤的資料,或者資料在傳輸過程中出錯,總之就是說B沒有收到想要的資料
  • A在超時計時器的設定時間內沒有收到確認,此時重發資料

所以可靠的TCP有32位元序列號和32位元確認號,TCP和UDP都有16位元校驗和。

連續ARQ協定


連續ARQ協定不會響應每個資料段,而是僅僅響應編號最大的這個資料段,表示之前的資料都收到了,這個叫做UNA模式,而停等ARQ協定可以看作是ACK模式

ACK + UNA

ARQ (自動重傳請求,Automatic Repeat-reQuest)模型響應有兩種方式:

  • UNA:此編號前所有包已收到
  • ACK:該編號包已收到

只用 UNA 將導致全部重傳,只用 ACK 則丟失成本太高,以往協定都是二選其一。而 kcp 協定中,除去單獨的 ACK 包(精確)外,所有包都有 UNA 資訊

非退讓流控

KCP正常模式同TCP一樣使用公平退讓法則,即傳送視窗大小由:傳送快取大小、接收端剩餘接收快取大小、丟包退讓、慢啟動這四要素決定,慢啟動是在剛開始傳送資料時讓視窗緩慢擴張,退半避讓是在網路擁堵時視窗大小減半,快重傳是在網路恢復時及時給予響應,與之配合的就是快恢復。但傳送及時性要求很高的小資料時,可選擇僅用前兩項來控制傳送頻率。以犧牲部分公平性及頻寬利用率之代價,換取了流暢傳輸的效果。KCP 實時性好,但頻寬利用率較低,因為:

  • 非退讓流控,不斷嘗試傳送資料,有效包不多
  • 每個包應答,佔用一定的頻寬

視窗協定中有兩種:

  • 擁塞視窗:防止過多的資料注入到網路中,這樣可以使網路中的路由器 和鏈路不至於過載。
  • 滑動視窗:接收方告知傳送方自己可以接收緩衝區的大小,通常與連續ARQ協定配合使用。

結構


大概流程如圖示,若是想深入探索底層實現,請參考原始碼或者參考連結中的詳解

參考連結