KCP技術原理
KCP是什麼
開源地址: https://github.com/skywind3000/kcp/tree/master
KCP是一個快速可靠協議,能以比 TCP浪費10%-20%的帶寬的代價,換取平均延遲降低 30%-40%,且最大延遲降低三倍的傳輸效果。純算法實現,並不負責底層協議(如UDP)的收發,需要使用者自己定義下層數據包的發送方式,並以 callback的方式提供給 KCP。
這裏翻譯一下,供參考
- KCP是一個ARQ協議:Automatic Repeat Query/Automatic repeat request,自動消息重發機制。
- 可靠協議,解決了丟包、亂序等問題。
- 可實現可靠UDP傳輸。不負責底層協議的收發,但是可以應用在幾乎任何底層協議上,比如UDP。
- 比TCP快速,延遲低。
實現原理
網絡模塊是非常重要基礎模塊,瞭解實現原理和實現細節非常重要。這關係到後續出現問題能否解決,根據項目情況進一步定製,甚至技術選型是否能通過等重要問題。
KCP實現了一整套與TCP類似/功能對應的機制,它們有:
- 超時重傳
- 快速重傳
- 滑動窗口
- 流量控制
- 擁塞控制
那我們為什麼不直接用TCP呢?或者説它為什麼比TCP快?
用作者的話説:TCP是為流量設計的(每秒內可以傳輸多少KB的數據),講究的是充分利用帶寬。而KCP是為流速設計的(單個數據包從一端發送到一端需要多少時間),以10%-20%帶寬浪費的代價換取了比 TCP快30%-40%的傳輸速度。
因為TCP在傳輸層,用户程序不能進行更多的定製,基於UDP的KCP就可以通過調節與TCP類似的機制中的一些設定,實現了下面的技術特性,達到了提高流速的效果。
- RTO翻倍vs不翻倍:TCP超時計算是RTOx2,這樣連續丟三次包就變成RTOx8了,十分恐怖,而KCP啓動快速模式後不x2,只是x1.5(實驗證明1.5這個值相對比較好),提高了傳輸速度。
- 選擇性重傳 vs 全部重傳:TCP丟包時會全部重傳從丟的那個包開始以後的數據,KCP是選擇性重傳,只重傳真正丟失的數據包。
- 快速重傳:發送端發送了1,2,3,4,5幾個包,然後收到遠端的ACK: 1, 3, 4, 5,當收到ACK3時,KCP知道2被跳過1次,收到ACK4時,知道2被跳過了2次,此時可以認為2號丟失,不用等超時,直接重傳2號包,大大改善了丟包時的傳輸速度。
- 延遲ACK vs 非延遲ACK :TCP為了充分利用帶寬,延遲發送ACK(NODELAY都沒用),這樣超時計算會算出較大RTT時間,延長了丟包時的判斷過程。KCP的ACK是否延遲發送可以調節。
- UNA vs ACK+UNA :ARQ模型響應有兩種,UNA(此編號前所有包已收到,如TCP)和ACK(該編號包已收到),光用 UNA會導致丟包時全部重傳,光用 ACK又會導致 ACK丟失成本太高。KCP有單獨ACK,且數據包和ACK包都帶UNA信息,有效降低ACK丟失成本。
- 非退讓流控:KCP正常模式同TCP一樣使用公平退讓法則,即發送窗口大小由:發送緩存大小、接收端剩餘接收緩存大小、丟包退讓及慢啓動這四要素決定。但傳送及時性要求很高的小數據時,可選擇通過配置跳過後兩步,僅用前兩項來控制發送頻率。以犧牲部分公平性及帶寬利用率之代價,換取了開着BT都能流暢傳輸的效果。
使用原理
以一個消息的收發為例:
- 使用socket接口搭建udp底層通信,例如C#的Socket API。
- 發送數據前,調用kcp的send接口,發送到kcp,進行數據包拆分、封裝。
- 設置kcp的output回調接口,數據包處理完成後,自動回調output接口。在這裏通過socket發送到服務器
- 服務器部分運行流程與客户端相同,這裏略過。消息處理完成後,服務器發包到客户端。
- 客户端的socket接口收到數據,調用kcp的input接口,kcp對數據包進行合併、解包。再通過回調接口,把真實的數據包返回給客户端進行邏輯處理。
接下來,結合大量現成的TCP資料的機制原理,一一講解KCP這些技術特性。