UDP與KCP詳解

UDP

以及TCP是什麼。我們知道傳輸層中有TCP和UDP兩種網絡協議,這節就講UDP是什麼。

Internet協議集支持一個無連接的傳輸協議,該協議稱爲用戶數據報協議(UDP,User Datagram Protocol)。UDP爲應用程序提供了一種無需建立連接就可以發送封裝的IP數據包的方法。RFC 768描述了UDP。

UDP API

圖片來自網絡

TCP與UDP的不同

UDP和TCP協議的主要區別是兩者在如何實現信息的可靠傳遞方面不同。TCP協議中包含了專門的傳遞保證機制,當數據接收方收到發送方傳來的信息時,會自動向發送方發出確認消息;發送方只有在接收到該確認消息之後才繼續傳送其它信息,否則將一直等待直到收到確認信息爲止。與TCP不同,UDP協議並不提供數據傳送的保證機制。如果在從發送方到接收方的傳遞過程中出現數據包的丟失,協議本身並不能做出任何檢測或提示。因此,通常人們把UDP協議稱爲不可靠的傳輸協議。

  • TCP是面向連接的傳輸控制協議,而UDP提供了無連接的數據報服務;
  • TCP 具有高可靠性,確保傳輸數據的正確性,不出現丟失或亂序;UDP 在傳輸數據前不建立連接,不對數據報進行檢查與修改,無須等待對方的應答,所以會出現分組丟失、重複、亂序,應用程序需要負責傳輸可靠性方面的所有工作;
  • UDP具有較好的實時性,工作效率較TCP協議高;
  • UDP段結構比 TCP的段結構簡單,因此網絡開銷也小。
  • TCP協議可以保證接收端毫無差錯地接收到發送端發出的字節流,爲應用程序提供可靠的通信服務。對可靠性要求高的通信系統往往使用TCP傳輸數據。

KCP

什麼是KCP

TCP優缺點:
我們知道TCP有超時重傳和滑動窗口機制提供了TCP的可靠性和流控特性,滑動窗口和擁塞控制可以使得TCP做到流量控制。但是TCP協議是從大局上考慮的,大公無私,經常犧牲自己速度來減少網絡擁塞。且TCP高度自治,很多參數沒法配置。
UDP優缺點:
UDP協議簡單,所以它更快。但是,UDP畢竟是不可靠的,應用層收到的數據可能是缺失、亂序的。

不管是端遊還是手遊,對於延時的要求都同樣重要,因爲延時直接關係到遊戲的體驗。並且不同的遊戲對延時的忍受程度不盡相同,例如:FPS延時超過了100ms體驗就不怎麼好了,Moba在這種程度卻覺得很好,MMO甚至到了200ms還可以愉快玩耍,但不管什麼遊戲,延時越低,體驗就越好。
TCP的特性導致網絡在不好的時候,延遲會變的很高。UDP的延遲很低,但是不可靠,亂序。

KCP是一種網絡傳輸協議(A Fast and Reliable ARQ Protocol),純算法實現,並不負責底層協議(如UDP)的收發,需要使用者自己定義下層數據包的發送方式,以callback的方式提供給KCP。連時鐘都需要外部傳遞進來,內部不會有任何一次系統調用。本文傳輸協議只考慮UDP的情況。
KCP基於UDP協議,在儘可能保留UDP快的前提下,借鑑了TCP的機制來保證可靠。KCP相比TCP浪費了10%~20%的帶寬代價,換取了平均延遲降低30%~40%,且最大延遲降低三倍的傳輸效果。

KCP是自私的,它只顧自己的傳輸效率,從不管整個網絡的擁塞情況。舉個例子,TCP檢測到丟包的時候,首先想到的是網絡擁塞了,要放慢自己的速度別讓網絡更糟,而KCP想到的趕緊重傳別耽誤事。

對比KCP和TCP:

  • KCP儘可能保留UDP快的特點下,保證可靠;TCP保證網絡絕對的可靠,所以設計複雜,速度慢。
  • KCP是爲流速設計的,重點是降低應用網絡延遲;TCP是爲流量設計的,可以充分利用帶寬。
  • KCP是應用層協議,底層是UDP;TCP是傳輸層協議。

用個比喻來形容就是TCP是條流速較慢但是流量很大的運河,而KCP是條水流湍急的小激流。

KCP協議只有 ikcp.h, ikcp.c兩個源文件,可以方便的集成到用戶自己的協議棧中。
圖片來自網絡:

KCP工作流程

KCP的工作流程如下圖所示:

 

圖中的send_queue是發送隊列,send_buf是發送緩衝區,rcv_buf是接收緩衝區,rcv_queue是接收隊列。隊列和緩衝區的實現都是雙向循環列表,通過宏定義來實現。queue和buff的結點就是一個kcp報文。

  • ikcp_update:循環定時調用

發送工作流程:

  • ikcp_send: 將用戶待發送的數據填充成KCP報文段,放入snd_queue。
  • ikcp_flush: 調用輸出回調將發送緩衝區中的數據發送出去。Ikcp_send不會將數據直接發送出去,只會將報文段放入snd_queue,等待下一次ikcp_update來調用ikcp_flush,將數據從snd_queue中移動到snd_buf後再發送數據。具體哪些報文可以發送,需要通過滑動窗口來控制,避免一次性發送太多的數據導致擁塞。

通過發送工作流程,可以發現發送數據需要等待flush,有發送延遲問題。普遍的解決方案是send之後立即調用一次update,但這樣做會帶來較大的系統開銷。

接收工作流程:

  • ikcp_input: 接收傳輸層數據,包括用戶數據報文段以及ACK報文;接收完後放入rcv_buff,等到接收完一段完整有序的報文之後,纔會移動到rcv_queue中供接收方處理。
  • ikcp_recv:從rcv_queue中讀取數據,觸發接收邏輯。

可靠性

ARQ協議(Automatic Repeat-reQuest),即自動重傳請求,是傳輸層的錯誤糾正協議之一,它通過使用確認和超時兩個機制,在不可靠的網絡上實現可靠的信息傳輸。TCP就是使用的ARQ協議來保證了數據的可靠。
ARQ協議有兩種模式:

  • ACK模式(停等ARQ協議),同步請求響應模式,基於超時重傳保證可靠。
  • UNA模式(連續ARQ協議),可以連續發送多個分組,而不必每發完一個分組就停下來等待對方確認,TCP就是如此。連續ARQ協議不會響應每個數據段,而是僅僅響應編號最大的這個數據段,表示之前的數據都收到了。

KCP的ARQ:光用UNA如果丟包將導致全部重傳,光用ACK則丟失成本太高。以往協議都是二選其一,而KCP有單獨ACK包,且數據包和ACK包都帶UNA信息,有效降低ACK丟失成本。

確認與重傳

KCP 確認重傳實現機制:ACK+UNA;超時重傳+快速重傳;選擇重傳

  • 在TCP中,有超時重傳機制,KCP中設置快速模式,可控制RTO成*1.5
  • 由於KCP的ARQ模式是ACK+UNA,所以KCP除了超時重傳還有選擇重傳機制
  • 選擇重傳:返回的ACK中包含rcv_nxt和sn。rcv_nxt代表收到的所有連續的包,sn代表哪些不連續的包收到了,那麼根據這兩個參數可以計算出來沒有收到的包的序號。發送方接收到接收方發過來的數據時,首先解析rcv_nxt,把所有小於rcv_nxt序號的包從發送緩存隊列中移除。然後再解析sn(大於rcv_nxt),遍歷發送緩存隊列,找到所有序號小於sn的包,就是被選擇重傳的包。
  • 快速重傳:根據我們設置的快速重傳的門限,對每個分片維護一個快速重傳的計數。每收到一個ACK解析sn後找到了一個分片,就把該分片的快速重傳的計數加一。如果該計數達到了快速重傳門限,那麼就認爲該分片已經丟失,可以觸發快速重傳。
  • KCP在發生快速重傳且數據包亂序時,採用的是TCP快恢復的策略。控制窗口調整爲已經發送沒有接收到ack的數據包數目的一半+resent。

流量控制

流量控制有兩機制:滑動窗口和擁塞控制。

滑動窗口的接收方告知發送方自己可以接收緩衝區的大小,通常與連續ARQ協議配合使用。滑動窗口就是TCP頭部的16位大小窗口字段,而UDP沒有這個字段。

擁塞控制的關鍵是四個算法:慢開始、擁塞避免、快速重傳、快速恢復。

KCP滑動窗口:
滑動窗口默認大小爲32,即可以接收最大爲32*MTU=43.75kB。KCP採用update的方式,更新間隔爲10ms,那麼KCP限定了你最大傳輸速率爲4375kB/s,在高網速傳輸大內容的情況下需要調用ikcp_wndsize調整接收與發送窗口。建議從應用側更好的控制發送流量與網絡速度持平,避免緩存堆積延遲。

KCP擁塞控制:
KCP的擁塞控制可以關閉。KCP的優勢在於可以完全關閉擁塞控制,非常自私的進行發送。KCP採用的擁塞控制策略爲TCP最古老的策略,無任何優勢。完全關閉擁塞控制,也不是一個最優策略,它全是會造成更爲擁堵的情況。

KCP VS TCP

  • TCP的RTO是直接翻倍,但是試驗測試發現RTO*=1.5比RTO*=2要好,所以KCP選擇了RTO*=1.5,提高了丟包時的傳輸速度。
  • 快速重傳:發送端發送了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 :TCP使用的UNA模式,有丟包全部重傳問題;KCP有單獨ACK,且數據包和ACK包都帶UNA信息,有效降低ACK丟失成本。
  • TCP丟包時會全部重傳從丟的那個包開始以後的數據;由於KCP使用了ACK+UNA模式,KCP是選擇性重傳,只重傳真正丟失的數據包。
  • 非退讓流控:KCP正常模式同TCP一樣使用公平退讓法則,即發送窗口大小由:發送緩存大小、接收端剩餘接收緩存大小、丟包退讓及慢啓動這四要素決定。但傳送及時性要求很高的小數據時,可選擇通過配置跳過後兩步,僅用前兩項來控制發送頻率。以犧牲部分公平性及帶寬利用率之代價,換取了開着BT都能流暢傳輸的效果。(KCP非退讓流控可以理解爲對及時性要求很高的小數據只考慮滑動窗口,看你發送窗口和接收窗口是否允許我傳輸

其他

  • 當用戶數據很大,大於一個UDP包能承擔的範圍時(大於mss),KCP會將用戶數據分片存儲在多個KCP包中。因此每個KCP包稱爲一個分片。
  • 用戶控制:擁塞控制可以取消、ACK回覆可以設置成無延遲ACK回覆、KCP的RTO可以控制成*1.5
  • KCP只是一套基於無連接的數據報文之上的連接和擁塞控制協議,對底層無連接的數據報文沒有具體的限制,可以基於UDP,也可以基於僞造的 TCP/ICMP等,也可以基於某些特殊環境的非internet網絡(比如各種現場通信總線)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章