http://blog.csdn.net/skywind/article/details/8804912
KCP是一個快速可靠協議,能以比 TCP浪費10%-20%的帶寬的代價,換取平均延遲降低 30%-40%,且最大延遲降低三倍的傳輸效果。純算法實現,并不負責底層協議(如UDP)的收發,需要使用者自己定義下層數據包的發送方式,并以 callback的方式提供給 KCP。連時鐘都需要外部傳遞進來,內部不會有任何一次系統調用。
整個協議只有 ikcp.h, ikcp.c兩個源文件,可以方便的集成到用戶自己的協議棧中。也許你實現了一個P2P,或者某個基于 UDP的協議,而缺乏一套完善的 ARQ可靠協議實現,那么簡單的拷貝這兩個文件到現有項目中,稍微編寫兩行代碼,即可使用。
技術特性
TCP是為流量設計的(每秒內可以傳輸多少KB的數據),講究的是充分利用帶寬。而KCP是為流速設計的(單個數據包從一端發送到一端需要多少時間),以10%-20%帶寬浪費的代價換取了比 TCP快30%-40%的傳輸速度。TCP信道是一條流速很慢,但每秒流量很大的大運河,而KCP是水流湍急的小激流。KCP有正常模式和快速模式兩種,通過以下策略達到提高流速的結果:
- 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(該編號包已收到),KCP有單獨ACK,且數據包和ACK包都帶UNA信息,有效降低ACK丟失成本。
- 非退讓流控:KCP正常模式同TCP一樣使用公平退讓法則,即發送窗口大小由:發送緩存大小、接收端剩余接收緩存大小、丟包退讓及慢啟動這四要素決定。但傳送及時性要求很高的小數據時,可選擇通過配置跳過后兩步,僅用前兩項來控制發送頻率。以犧牲部分公平性及帶寬利用率之代價,換取了開著BT都能流暢傳輸的效果。
基本使用
- 創建 KCP對象:
// 初始化 kcp對象,conv為一個表示會話編號的整數,和tcp的 conv一樣,通信雙方需要 // 保證 conv相同,相互的數據包才能夠被認可,user是一個給回調函數的指針。 ikcpcb *kcp = ikcp_create(conv, user);
- 設置回調函數:
// KCP的下層協議輸出函數,KCP需要發送數據時會調用它 // buf/len 表示緩存和長度 // user指針為 kcp對象創建時傳入的值,用于區別多個 KCP對象 int udp_output(const char *buf, int len, ikcpcb *kcp, void *user) { .... } // 設置回調函數 kcp->output = udp_output;
- 循環調用 update:
// 以一定頻率調用 ikcp_update來更新 kcp狀態,并且傳入當前的時鐘(毫秒單位)。 // 比如 10ms調用一次,或用 ikcp_check確定下次調用 update的時間不必每次調用。 ikcp_update(kcp, millisec);
- 輸入一個下層數據包:
// 收到一個下層數據包(比如UDP包)時需要調用: ikcp_input(kcp, received_udp_packet, received_udp_size);
處理了下層協議的輸出/輸入后 KCP協議就可以正常工作了,使用 ikcp_send(kcp, ptr, size)來向遠端發送數據。而另一端使用ikcp_recv(kcp, ptr, size)來接收數據。
協議配置
協議默認模式是一個標準的 ARQ,需要通過配置打開各項加速開關:
- 工作模式
int ikcp_nodelay(ikcpcb *kcp, int nodelay, int interval, int resend, int nc);
- nodelay :是否啟用 nodelay模式,0不啟用;1啟用。
- interval :協議內部工作的 interval,單位毫秒,比如 10ms或者 20ms
- resend :快速重傳模式,默認0關閉,可以設置2(2次ACK跨越將會直接重傳)
- nc :是否關閉流控,默認是0代表不關閉,1代表關閉。
普通模式:`ikcp_nodelay(kcp, 0, 40, 0, 0); 極速模式: ikcp_nodelay(kcp, 1, 10, 2, 1);
該調用將會設置協議的最大發送窗口和最大接收窗口大小,默認為32.
純算法協議并不負責探測 MTU,默認 mtu是1400字節,可以使用ikcp_setmtu來設置該值。該值將會影響數據包歸并及分片時候的最大傳輸單元。
不管是 TCP還是 KCP計算 RTO時都有最小 RTO的限制,即便計算出來RTO為40ms,由于默認的 RTO是100ms,協議只有在100ms后才能檢測到丟包,快速模式下該值為30ms,可以手動更改該值:kcp->rx_minrto = 10;
內存分配器
默認KCP協議使用 malloc/free進行內存分配釋放,如果應用層接管了內存分配,可以用ikcp_allocator來設置新的內存分配器,注意要在一開始設置:
ikcp_allocator(my_new_malloc, my_new_free);
前向糾錯
為了進一步提高傳輸速度,下層協議也許會使用前向糾錯技術。需要注意,前向糾錯會根據冗余信息解出原始數據包。相同的原始數據包不要兩次input到KCP,否則將會導致kcp以為對方重發了,這樣會產生更多的ack占用額外帶寬。
比如下層協議使用最簡單的冗余包:單個數據包除了自己外,還會重復存儲一次上一個數據包,以及上上一個數據包的內容:
Fn = (Pn, Pn-1, Pn-2) P0 = (0, X, X) P1 = (1, 0, X) P2 = (2, 1, 0) P3 = (3, 2, 1)
這樣幾個包發送出去,接收方對于單個原始包都可能被解出3次來(后面兩個包任然會重復該包內容),那么這里需要記錄一下,一個下層數據包只會input給kcp一次,避免過多重復ack帶來的浪費。
http://blog.csdn.net/kxg99/article/details/50696336
如果不丟包那么 KCP()和 TCP性能差不多,KCP不會有任何優勢,但是網絡會卡,造成卡的原因就是丟包和抖動,有同學在內網這樣好的環境下沒有用任何丟包模擬直接跑,跑出來的數據是差不多的,但是放到公網上,放到3G/4G網絡情況下,差距就很明顯了,公網在高峰期有平均接近10%的丟包,wifi/3g/4g下更糟糕,這正是造成各種網絡卡頓的元兇。
感謝asio-kcp的作者 zhangyuan 對 KCP 與 enet, udt做過的一次橫向評測,結論如下:
- ASIO-KCP hasgood performace in wifi and phone network(3G, 4G).
- Extra using 20% ~ 50% network flow for speed improvement.
- The kcp is the first choice for realtime pvp game.
- The lag is less than 1 second when network lag happen.3 times better than enetwhen lag happen.
- The enet is a good choice if your game allow 2 second lag.
- UDT is a bad idea.It always sink into badly situation of more than serval seconds lag. And the recovery is not expected.
- enet has the problem of lack of doc. And it has lots of functions that you may intrest. kcp’s doc is chinese. Good thing is the function detail which is writen in code is english. And you can use asio_kcp which is a good wrap.
- The kcp is a simple thing. You will write more code if you want more feature.
- UDT has a perfect doc. UDT may has more bug than others as I feeling.
具體見:橫向比較和這里。截取一段在網絡糟糕時,asio-kcp/enet的延遲數據:
worst network lag happen:
asio: 10:51.21
291 295 269 268 231 195 249 230 225 204
enet: 10:51.21
1563 1520 1470 1482 1438 1454 1412 1637 1588 1540
posted on 2017-12-08 16:22
思月行云 閱讀(1450)
評論(0) 編輯 收藏 引用 所屬分類:
C\C++