:zap: KCP - A Fast and Reliable ARQ Protocol

Overview

KCP - A Fast and Reliable ARQ Protocol

Powered Build Status Backers on Open Collective Sponsors on Open Collective

README in English

简介

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(该编号包已收到),光用UNA将导致全部重传,光用ACK则丢失成本太高,以往协议都是二选其一,而 KCP协议中,除去单独的 ACK包外,所有包都有UNA信息。

非退让流控:

KCP正常模式同TCP一样使用公平退让法则,即发送窗口大小由:发送缓存大小、接收端剩余接收缓存大小、丢包退让及慢启动这四要素决定。但传送及时性要求很高的小数据时,可选择通过配置跳过后两步,仅用前两项来控制发送频率。以牺牲部分公平性及带宽利用率之代价,换取了开着BT都能流畅传输的效果。

快速安装

您可以使用vcpkg库管理器下载并安装kcp:

git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install kcp

vcpkg中的kcp库由Microsoft团队成员和社区贡献者保持最新状态。如果版本过时,请在vcpkg存储库上创建issue或提出PR

基本使用

  1. 创建 KCP对象:

    // 初始化 kcp对象,conv为一个表示会话编号的整数,和tcp的 conv一样,通信双
    // 方需保证 conv相同,相互的数据包才能够被认可,user是一个给回调函数的指针
    ikcpcb *kcp = ikcp_create(conv, user);
  2. 设置回调函数:

    // KCP的下层协议输出函数,KCP需要发送数据时会调用它
    // buf/len 表示缓存和长度
    // user指针为 kcp对象创建时传入的值,用于区别多个 KCP对象
    int udp_output(const char *buf, int len, ikcpcb *kcp, void *user)
    {
      ....
    }
    // 设置回调函数
    kcp->output = udp_output;
  3. 循环调用 update:

    // 以一定频率调用 ikcp_update来更新 kcp状态,并且传入当前时钟(毫秒单位)
    // 如 10ms调用一次,或用 ikcp_check确定下次调用 update的时间不必每次调用
    ikcp_update(kcp, millisec);
  4. 输入一个下层数据包:

    // 收到一个下层数据包(比如UDP包)时需要调用:
    ikcp_input(kcp, received_udp_packet, received_udp_size);

    处理了下层协议的输出/输入后 KCP协议就可以正常工作了,使用 ikcp_send 来向 远端发送数据。而另一端使用 ikcp_recv(kcp, ptr, size)来接收数据。

协议配置

协议默认模式是一个标准的 ARQ,需要通过配置打开各项加速开关:

  1. 工作模式:

    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);
  2. 最大窗口:

    int ikcp_wndsize(ikcpcb *kcp, int sndwnd, int rcvwnd);

    该调用将会设置协议的最大发送窗口和最大接收窗口大小,默认为32. 这个可以理解为 TCP的 SND_BUF 和 RCV_BUF,只不过单位不一样 SND/RCV_BUF 单位是字节,这个单位是包。

  3. 最大传输单元:

    纯算法协议并不负责探测 MTU,默认 mtu是1400字节,可以使用ikcp_setmtu来设置该值。该值将会影响数据包归并及分片时候的最大传输单元。

  4. 最小RTO:

    不管是 TCP还是 KCP计算 RTO时都有最小 RTO的限制,即便计算出来RTO为40ms,由于默认的 RTO是100ms,协议只有在100ms后才能检测到丢包,快速模式下为30ms,可以手动更改该值:

    kcp->rx_minrto = 10;

文档索引

协议的使用和配置都是很简单的,大部分情况看完上面的内容基本可以使用了。如果你需要进一步进行精细的控制,比如改变 KCP的内存分配器,或者你需要更有效的大规模调度 KCP链接(比如 3500个以上),或者如何更好的同 TCP结合,那么可以继续延伸阅读:

开源案例

  • kcptun: 基于 kcp-go做的高速远程端口转发(隧道) ,配合ssh -D,可以比 shadowsocks 更流畅的看在线视频。
  • dog-tunnel: GO开发的网络隧道,使用 KCP极大的改进了传输速度,并移植了一份 GO版本 KCP
  • v2ray: 著名代理软件,Shadowsocks 代替者,1.17后集成了 kcp协议,使用UDP传输,无数据包特征。
  • HP-Socket: 高性能网络通信框架 HP-Socket。
  • frp: 高性能内网穿透的反向代理软件,可将将内网服务暴露映射到外网服务器。
  • asio-kcp: 使用 KCP的完整 UDP网络库,完整实现了基于 UDP的链接状态管理,会话控制,KCP协议调度等
  • kcp-java: Java版本 KCP协议实现。
  • kcp-netty: kcp的Java语言实现,基于netty。
  • java-kcp: JAVA版本KCP,基于netty实现(包含fec功能)
  • csharp-kcp: csharp版本KCP,基于dotNetty实现(包含fec功能)
  • kcp-go: 高安全性的kcp的 GO语言实现,包含 UDP会话管理的简单实现,可以作为后续开发的基础库。
  • kcp-csharp: kcp的 csharp移植,同时包含一份回话管理,可以连接上面kcp-go的服务端。
  • kcp-csharp: 新版本 Kcp的 csharp移植。线程安全,运行时无alloc,对gc无压力。
  • kcp-rs: KCP的 rust移植
  • kcp-rust:新版本 KCP的 rust 移植
  • tokio-kcp:rust tokio 的 kcp 集成
  • lua-kcp: KCP的 Lua扩展,用于 Lua服务器
  • node-kcp: node-js 的 KCP 接口
  • nysocks: 基于libuv实现的node-addon,提供nodejs版本的代理服务,客户端接入支持SOCKS5和ss两种协议
  • shadowsocks-android: Shadowsocks for android 集成了 kcptun 使用 kcp协议加速 shadowsocks,效果不错
  • kcpuv: 使用 libuv开发的kcpuv库,目前还在 Demo阶段
  • Lantern:更好的 VPN,Github 50000 星,使用 kcpgo 加速
  • rpcx :RPC 框架,1000+ 星,使用 kcpgo 加速 RPC
  • xkcptun: c语言实现的kcptun,主要用于OpenWrt, LEDE开发的路由器项目上
  • et-frame: C#前后端框架(前端unity3d),统一用C#开发游戏,实现了前后端kcp协议
  • yasio: 一个跨平台专注于任意客户端程序的异步socket库, 易于使用,相同的API操作KCP/TCP/UDP, 性能测试结果: benchmark-pump.
  • gouxp: 用Go实现基于回调方式的KCP开发包,包含加解密和FEC支持,简单易用。

商业案例

  • 明日帝国:Game K17 的 《明日帝国》 (Google Play),使用 KCP 加速游戏消息,让全球玩家流畅联网
  • 仙灵大作战:4399 的 MOBA游戏,使用 KCP 优化游戏同步
  • CC:网易 CC 使用 kcp 加速视频推流,有效提高流畅性
  • BOBO:网易 BOBO 使用 kcp 加速主播推流
  • 云帆加速:使用 KCP 加速文件传输和视频推流,优化了台湾主播推流的流畅度
  • SpatialOS: 大型多人分布式游戏服务端引擎,BigWorld 的后继者,使用 KCP 加速数据传输。

欢迎告知更多案例

协议比较

如果网络永远不卡,那 KCP/TCP 表现类似,但是网络本身就是不可靠的,丢包和抖动无法避免(否则还要各种可靠协议干嘛)。在内网这种几乎理想的环境里直接比较,大家都差不多,但是放到公网上,放到3G/4G网络情况下,或者使用内网丢包模拟,差距就很明显了。公网在高峰期有平均接近10%的丢包,wifi/3g/4g下更糟糕,这些都会让传输变卡。

感谢 asio-kcp 的作者 zhangyuan 对 KCP 与 enet, udt做过的一次横向评测,结论如下:

  • ASIO-KCP has good performace in wifi and phone network(3G, 4G).
  • 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 enet when 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.

具体见:横向比较评测数据,为犹豫选择的人提供了更多指引。

大型多人游戏服务端引擎 SpatialOS 在集成 KCP 协议后做了同 TCP/RakNet 的评测:

对比了在服务端刷新率为 60 Hz 同时维护 50 个角色时的响应时间,详细对比报告见:

关于协议

近年来,网络游戏和各类社交网络都在成几何倍数的增长,不管网络游戏还是各类互动社交网络,交互性和复杂度都在迅速提高,都需要在极短的时间内将数据同时投递给大量用户,因此传输技术自然变为未来制约发展的一个重要因素,而开源界里各种著名的传输协议,如 raknet/enet 之类,一发布都是整套协议栈一起发布,这种形式是不利于多样化的,我的项目只能选择用或者不用你,很难选择 “部分用你”,然而你一套协议栈设计的再好,是非常难以满足不同角度的各种需求的。

因此 KCP 的方式是把协议栈 “拆开”,让大家可以根据项目需求进行灵活的调整和组装,你可以下面加一层 reed solomon 的纠删码做 FEC,上面加一层类 RC4/Salsa20 做流加密,握手处再设计一套非对称密钥交换,底层 UDP 传输层再做一套动态路由系统,同时探测多条路径,选最好路径进行传输。这些不同的 “协议单元” 可以像搭建积木一般根据需要自由组合,保证 “简单性” 和 “可拆分性”,这样才能灵活适配多变的业务需求,哪个模块不好,换了就是。

未来传输方面的解决方案必然是根据使用场景深度定制的,因此给大家一个可以自由组合的 “协议单元” ,方便大家集成在自己的协议栈中。

For more information, please see the Success Stories.

关于作者

作者:林伟 (skywind3000)

欢迎关注我的:twitterzhihu

我在多年的开发经历中,一直都喜欢研究解决程序中的一些瓶颈问题,早年喜欢游戏开发,照着《VGA编程》来做游戏图形,读 Michael Abrash 的《图形程序开发人员指南》做软渲染器,爱好摆弄一些能够榨干 CPU 能够运行更快的代码,参加工作后,兴趣转移到服务端和网络相关的技术。

2007 年时做了几个传统游戏后开始研究快速动作游戏的同步问题,期间写过不少文章,算是国内比较早研究同步问题的人,然而发现不管怎么解决同步都需要在网络传输方面有所突破,后来离开游戏转行互联网后也发现不少领域有这方面的需求,于是开始花时间在网络传输这个领域上,尝试基于 UDP 实现一些保守的可靠协议,仿照 BSD Lite 4.4 的代码实现一些类 TCP 协议,觉得比较有意思,又接着实现一些 P2P 和动态路由网相关的玩具。KCP 协议诞生于 2011 年,基本算是自己传输方面做的几个玩具中的一个。

Kcptun 的作者 xtaci 是我的大学同学,我俩都是学通信的,经常在一起研究如何进行传输优化。

欢迎捐赠

欢迎使用支付宝对该项目进行捐赠

欢迎使用支付宝手扫描上面的二维码,对该项目进行捐赠。捐赠款项将用于持续优化 KCP协议以及完善文档。

感谢:明明、星仔、进、帆、颁钊、斌铨、晓丹、余争、虎、晟敢、徐玮、王川、赵刚强、胡知锋、万新朝、何新超、刘旸、侯宪辉、吴佩仪、华斌、如涛、胡坚。。。(早先的名单实在不好意思没记录下来)等同学的捐助与支持。

欢迎关注

KCP交流群:364933586(QQ群号),KCP集成,调优,网络传输以及相关技术讨论

Gitter 群:https://gitter.im/skywind3000/KCP

blog: http://www.skywind.me

Contributors

This project exists thanks to all the people who contribute.

Issues
  • 网速很快的情况下TCP可达50Mb(即5.2MB字节)但是KCP速度跟不上。

    网速很快的情况下TCP可达50Mb(即5.2MB字节)但是KCP速度跟不上。

    本机发送的最高速度只能达到17MB(约120Mb左右的速度)。 试过很过参数也不知道怎么把速度提升。 在网络速度不快的互联网,网速在10Mb即1.2MB字节左右的时候,基本上速度都和TCP差不多,比TCP慢一些,KCP在50Mb-100Mb和TCP差距很大,只有一半的样子甚至不到一半的样子。 我们主要用来发送和接收大文件用。 发送和接收的缓存,我设置成2048了,网络的RTT=17-35。 是不是可以将滑动窗口设置一下?但是不知道怎么设置。 const IUINT32 IKCP_CMD_PUSH = 81; // cmd: push data const IUINT32 IKCP_CMD_ACK = 82; // cmd: ack const IUINT32 IKCP_CMD_WASK = 83; // cmd: window probe (ask) const IUINT32 IKCP_CMD_WINS = 84; // cmd: window size (tell) 这地方是不是可以设置?有的修改后发现不能运行挂了,不知道作用是什么。 不知道哪里可以设置,该设置的参数都设置了。。。 请帮帮忙,感谢!!!

    opened by whrtqa 139
  • deadlink的问题

    deadlink的问题

    源码中有如下片段: if (segment->xmit >= kcp->dead_link) { kcp->state = (IUINT32)-1; } 这代码是否意味着某个分片已经重发过很多次(默认20次),始终没有得到对方的ACK? 有点纳闷为什么这里没有对应一个callback。上层判断到state为-1时应该如何处理?是否应该认为连接已经断开?

    opened by huyuguang 20
  • Is there anyone who has experience of live streaming optimization by using KCP?

    Is there anyone who has experience of live streaming optimization by using KCP?

    We, KINGSOFT Cloud inc., are investigating whether there is a way to improve the user's live-stream play experience, and reducing latency over RTMP protocol over tcp what we are using. We have our own Streamer and Player SDK, so it's possible to embed KCP on it. Please comments this issue to help us. Thanks a lot!!

    opened by gnolizuh 17
  • KCP和TCP的比较

    KCP和TCP的比较

    我尝试了一把KCP,测试KCP和TCP的延时情况,测试方法和自带的测试程序相似:

    每20ms发送一个1k的数据包,发送1000次,统计数据来回的最大延时和平均延时 KCP配置为快速模式,TCP和KCP服务器都为简单的echo服务,每1ms调用一次updata()

    **1.**在内网环境下,KCP完全没有优势,TCP的平均延时小于1ms,kcp的延时约9ms

    **2.**在外网(有线)环境下,平均延时TCP(7ms),KCP(15ms)依然没有优势,只是KCP(50ms)的最大延时小于TCP(秒级),且没有大的抖动,TCP有时会出现秒级的延时,而KCP很少出现这种情况

    **3.**在4G环境下(移动4G),和外网环境下测试结果相似,KCP(65ms)的平均延时高于TCP(55ms),同样的,TCP(1秒左右)比KCP(350ms)有更大的抖动

    **4.**我现在应用场景是客户端(手机)一发一收(需要收到回应才发下一个包),约30次小于1k的数据交互,其中有几次交互需要延时小于90ms,目前用TCP有失败的概率,想用KCP改善(降低整个流程的交互时间,提高用户体验,减少失败概率)

    **5.**从结果上来看,KCP显得很鸡肋,从移动应用的角度看,他花费了更多的流量,并没有换取延时的降低(指平均延时)

    **6.**可能是我测试程序不能体现出KCP的优势,我想知道您是 怎么测试得出 “能以比 TCP浪费10%-20%的带宽的代价,换取平均延迟降低 30%-40%” ,或者源码的目录里能否把这份测试程序公开,这样我也能比较信服的接受

    **7.**如果只是做收发数据耗时的测试(10M数据测试,每个包1k),TCP是一发一收数据的统计和,而UDP并非一发一收,单个数据包来回的延时都是秒级的,但总的耗时是低于TCP的,只有TCP的20%,但如果KCP也写成收到一个包才发送下一个包的话,两者并没有多少差距

    写了很多,1是希望得到解答,2是希望楼主能把KCP的应用场景再明确一下

    opened by LiTianjue 16
  • KCP 测速结果

    KCP 测速结果

    一下是对于 Kcp-go 的测速结果,但是我觉得C语言实现也会有同样的问题,想来请教一下。

    我自己用go语言实现了iperf测速工具, 实现了基本的一些测速功能, 最主要的就是加上了对于自定义应用层协议的扩展, 所以也可以用来对kcp进行更精确地测速.因为 Fast.com 之类的还是涉及到了3个点的传输。

    然后一个有趣的现象就是, 对于我自身的网络情况:

    • PC: 广东某高校校园网, 时好时坏, 阿门~
    • Server: Location: LA Latency(Ping): 170ms 左右 搬瓦工 CN2, 号称百兆带宽
    • KCP 版本: May 8, 2019 最新版 ( go get 下来 )

    在上行情况下,用适当的参数,确实 KCP 的表现会比 TCP 好一些,大约有40%-50%提升 :

    // KCP 结果, 平均带宽在 17.69Mb/s 左右
    >.\iperf-go.exe -c <server_ip> -proto kcp -sw 512  // KCP 发送窗口512, 不开启FEC, 加密  
    09:55:23.790 0 ▶ INFO 001 Go-logging init finish
    Iperf started:
    addr:104.224.137.244    port:5201       proto:rudp      interval:1000   duration:10     NoDelay:false   burst:true      BlockSize:4096  StreamNum:1
    RUDP settting: sndWnd:512       rcvWnd:512      writeBufSize:4096Kb     readBufSize:4096Kb      noCongestion:true       flushInterval:10
    Connect to server 104.224.137.244:5201 succeed.
    [ ID]    Interval        Transfer        Bandwidth        RTT      Retrans   Retrans(%)  Lost(%)  Early Retrans  Fast Retrans
    [  0] 0.00-1.00 sec      3.73 MB        29.81 Mb/s       165.0ms          11    0.39%   0.39%   0.00%   0.00%
    [  0] 1.00-2.00 sec      2.47 MB        19.78 Mb/s       169.0ms         600    31.84%  22.50%  9.34%   0.00%
    [  0] 2.00-3.00 sec      2.50 MB        20.03 Mb/s       166.0ms         356    18.66%  13.31%  5.35%   0.00%
    [  0] 3.00-4.00 sec      1.85 MB        14.78 Mb/s       169.0ms         844    59.94%  44.67%  15.27%  0.00%
    [  0] 4.00-5.00 sec      2.32 MB        18.56 Mb/s       165.0ms         606    34.27%  17.53%  16.74%  0.00%
    [  0] 5.00-6.00 sec      1.54 MB        12.34 Mb/s       174.0ms         922    78.41%  48.14%  30.28%  0.00%
    [  0] 6.00-7.00 sec      1.93 MB        15.41 Mb/s       199.0ms         852    58.06%  51.17%  6.88%   0.00%
    [  0] 7.00-8.00 sec      1.69 MB        13.50 Mb/s       167.0ms         499    38.80%  18.97%  19.83%  0.00%
    [  0] 8.00-9.00 sec      2.45 MB        19.56 Mb/s       183.0ms         842    45.19%  28.33%  16.85%  0.00%
    [  0] 9.00-10.04 sec     1.64 MB        13.16 Mb/s       181.0ms         996    79.48%  39.98%  39.50%  0.00%
    - - - - - - - - - - - - - - - - SUMMARY - - - - - - - - - - - - - - - -
    [ ID]    Interval        Transfer        Bandwidth        RTT      Retrans   Retrans(%)  Lost(%)  Early Retrans  Fast Retrans
    [  0] 0.00-10.04 sec    22.12 MB        17.69 Mb/s       173.8ms        6528    38.73%  25.03%  13.71%  0.00%   [SENDER]
    
    // TCP 结果, 平均带宽在 12.10Mb/s 左右, 在发送端为windows系统的情况下拿不到 retrans 数据
    >.\iperf-go.exe -c 104.224.137.244 -proto tcp  
    09:56:23.161 0 ▶ INFO 001 Go-logging init finish
    Iperf started:
    addr:104.224.137.244    port:5201       proto:tcp       interval:1000   duration:10     NoDelay:false   burst:true      BlockSize:131072        StreamNum:1
    Connect to server 104.224.137.244:5201 succeed.
    [ ID]    Interval        Transfer        Bandwidth        RTT      Retrans   Retrans(%)
    [  0] 0.00-1.00 sec      1.50 MB        12.00 Mb/s         0.0ms           0    0.00%
    [  0] 1.00-2.00 sec      5.38 MB        43.00 Mb/s         0.0ms           0    0.00%
    [  0] 2.00-3.01 sec      0.12 MB         1.00 Mb/s         0.0ms           0    0.00%
    [  0] 3.01-4.00 sec      0.00 MB         0.00 Mb/s         0.0ms           0    NaN%
    [  0] 4.00-5.00 sec      0.75 MB         6.00 Mb/s         0.0ms           0    0.00%
    [  0] 5.00-6.00 sec      2.62 MB        21.00 Mb/s         0.0ms           0    0.00%
    [  0] 6.00-7.00 sec      3.62 MB        29.00 Mb/s         0.0ms           0    0.00%
    [  0] 7.00-8.01 sec      0.12 MB         1.00 Mb/s         0.0ms           0    0.00%
    [  0] 8.01-9.00 sec      0.38 MB         3.00 Mb/s         0.0ms           0    0.00%
    [  0] 9.00-10.27 sec     0.62 MB         5.00 Mb/s         0.0ms           0    0.00%
    - - - - - - - - - - - - - - - - SUMMARY - - - - - - - - - - - - - - - -
    [ ID]    Interval        Transfer        Bandwidth        RTT      Retrans   Retrans(%)
    [  0] 0.00-10.27 sec    15.12 MB        12.10 Mb/s         NaNms           0    0.00%   [SENDER]
    

    但是在下行的情况下(TCP有BBR支持),TCP的表现则好很多,快有 KCP 的一倍。并且我也调整过KCP的一些参数,均未获得较好的效果(例如调整snd_wnd, buffer之类)

    // KCP 结果,大概在 8.05 Mb/s 左右(这还是经过几次尝试在比较好的结果下)
    
    >.\iperf-go.exe -c 104.224.137.244 -proto rudp -sw 512 –R (客户端)
    22:04:39.175 0 ▶ INFO 001 Go-logging init finish
    Server listening on 5201
    Accept connection from client: 221.4.34.225:42032
    [ ID]    Interval        Transfer        Bandwidth        RTT      Retrans   Retrans(%)  Lost(%)  Early Retrans  Fast Retrans
    [  0] 0.00-1.00 sec	 1.23 MB	 9.84 Mb/s	 172.0ms	 713	76.04%	7.47%	68.57%	0.00%
    [  0] 1.00-2.00 sec	 0.99 MB	 7.91 Mb/s	 172.0ms	 956	126.94%	49.13%	77.81%	0.00%
    [  0] 2.00-3.00 sec	 0.96 MB	 7.69 Mb/s	 172.0ms	 766	104.60%	21.99%	82.62%	0.00%
    [  0] 3.00-4.00 sec	 0.84 MB	 6.75 Mb/s	 176.0ms	1201	186.79%	65.94%	120.84%	0.00%
    [  0] 4.00-5.00 sec	 0.95 MB	 7.59 Mb/s	 174.0ms	1125	155.53%	33.87%	121.66%	0.00%
    [  0] 5.00-6.00 sec	 1.30 MB	10.44 Mb/s	 174.0ms	 849	85.39%	36.21%	49.18%	0.00%
    [  0] 6.00-7.00 sec	 1.09 MB	 8.69 Mb/s	 173.0ms	 863	104.29%	48.34%	55.95%	0.00%
    [  0] 7.00-8.00 sec	 1.09 MB	 8.75 Mb/s	 172.0ms	 818	98.14%	34.91%	63.23%	0.00%
    [  0] 8.00-9.00 sec	 0.47 MB	 3.75 Mb/s	 171.0ms	 911	255.03%	106.10%	148.93%	0.00%
    [  0] 9.00-10.27 sec	 1.13 MB	 9.06 Mb/s	 180.0ms	1096	126.96%	65.10%	61.86%	0.00%
    - - - - - - - - - - - - - - - - SUMMARY - - - - - - - - - - - - - - - -
    [ ID]    Interval        Transfer        Bandwidth        RTT      Retrans   Retrans(%)  Lost(%)  Early Retrans  Fast Retrans
    [  0] 0.00-10.27 sec	10.06 MB	 8.05 Mb/s	 173.6ms	9298	121.30%	42.56%	78.75%	0.00%	[SENDER]
    
    // TCP BBR结果, 大概在20.40Mb/s左右
    >.\iperf-go.exe -c 104.224.137.244 –R  (客户端)
    22:04:17.793 0 ▶ INFO 001 Go-logging init finish
    Server listening on 5201
    Accept connection from client: 221.4.34.225:22567
    [ ID]    Interval        Transfer        Bandwidth        RTT      Retrans   Retrans(%)
    [  0] 0.00-1.00 sec	 1.50 MB	12.00 Mb/s	 172.6ms	   0	0.00%
    [  0] 1.00-2.00 sec	 3.12 MB	25.00 Mb/s	 169.1ms	   0	0.00%
    [  0] 2.00-3.00 sec	 2.75 MB	22.00 Mb/s	 205.3ms	 378	19.14%
    [  0] 3.00-4.00 sec	 2.00 MB	16.00 Mb/s	 164.8ms	1490	103.73%
    [  0] 4.00-5.00 sec	 4.75 MB	38.00 Mb/s	 162.9ms	 873	25.59%
    [  0] 5.00-6.00 sec	 1.25 MB	10.00 Mb/s	 163.3ms	   0	0.00%
    [  0] 6.00-7.00 sec	 2.50 MB	20.00 Mb/s	 163.3ms	   0	0.00%
    [  0] 7.00-8.00 sec	 2.62 MB	21.00 Mb/s	 163.5ms	   6	0.32%
    [  0] 8.00-9.00 sec	 2.38 MB	19.00 Mb/s	 162.7ms	   0	0.00%
    [  0] 9.00-10.19 sec	 2.50 MB	20.00 Mb/s	 163.1ms	   0	0.00%
    - - - - - - - - - - - - - - - - SUMMARY - - - - - - - - - - - - - - - -
    [ ID]    Interval        Transfer        Bandwidth        RTT      Retrans   Retrans(%)
    [  0] 0.00-10.19 sec	25.50 MB	20.40 Mb/s	 169.1ms	2747	0.15%	[SENDER]
    

    通过其他参数可发现, KCP无论上行还是下行情况下丢包率都异常地高(30%,40%以上),再加上early resend的策略的话在下行的report中可以发现,重传的包量甚至已经超过了本身的包量(也就是说平均下来每个包都发了两次多)

    这么来看在 UDP 上搭建可靠传输还是值得商榷的,这么高的丢包率可能与ISP对UDP流量的管制有关。

    这里还想讨论的就是,

    • 为什么上行下行丢包率会有这么大的差距?(KCP表现不好基本是由于丢包引起的)
    • 对于这样的网络状况有没有什么优化策略?
    • 然后我自己在 KCP 的基础上实现了 BBR 拥塞控制,包含了 pacing 和 cwnd 的调整策略,效果相较 KCP 有略微的提升(在丢包率和带宽上),但是依旧有较高的丢包率,感觉要摊手了 Orz

    iperf-go 测试工具: https://github.com/ZezhongWang/iperf-go 欢迎使用!

    opened by ZezhongWang 10
  • Android中应用无法回传ack

    Android中应用无法回传ack

    我的需求是Android APP通过kcp将音视频数据发送到同一局域网下的其他Android手机上,现在我发送端能正常发送(数据流无法确定是否正确),在接收端接收到数据后无法正常组包,查看资料说还需要回传ack,请问ack是需要接收端再次通过udp将收到的包再以IKCP_CMD_ACK的cmd发送给发送端吗

    opened by GadusBetter 9
  • 请问ikcp_input返回值为0,但是ikcp_recv返回-1是怎么回事?

    请问ikcp_input返回值为0,但是ikcp_recv返回-1是怎么回事?

    请问我项目中每成功接收到一个包之后,再来一个包ikcp_input返回值不为负数(为0),但是ikcp_recv返回-1是怎么回事?

    每次都是 if (iqueue_is_empty(&kcp->rcv_queue)) return -1;

    这是正常的吗? 我是否判断ikcp_input只要成功, ikcp_recv返回-1就直接忽略呢? 还是说我有bug?

    opened by woshi91 9
  • 能不能和raknet比较一下。

    能不能和raknet比较一下。

    或者是,如何评价raknet呢? http://www.jenkinssoftware.com/ https://github.com/OculusVR/RakNet

    因为之前做了个商业rts游戏,山寨lol。用的是raknet,一切都很好。 所以能不能以你的专业眼光来比较或评价一下raknet。好让我下一次有选择或者项目重做的话,能选择你的kcp呢。

    opened by heroboy 9
  • 电信4G打开流控,速度非常慢

    电信4G打开流控,速度非常慢

    ikcp_nodelay(kcp, 0, 40, 0, 0); nc :是否关闭流控,默认是0代表不关闭,1代表关闭。 使用普通模式/急速模式都相同,只要是nc设置为0,则电信4G的速度为0.2M/S(很多时候还卡着不动了),如果设置为1即关闭流控,速度稳定达到0.9M/S。 其他的网络包括长宽和移动,都没有这个问题,无论打开流控速度和没有打开流控速度差不多,电信4G差别非常大,或者还有其他的网络没有碰到。 请大神帮帮忙,指点迷路,感谢!!!

    opened by whrtqa 8
  • ikcp_recv 第二次启动程序一直等于-1

    ikcp_recv 第二次启动程序一直等于-1

    我写了一个视频 推流 和 拉流 ,用kcp来连接。
    2端可以正常播放,但是 当我把 拉流 的这端的程序给杀死以后, 推流 这端继续推流, 拉流这端重新打开,连接kcp,代码如下: c_kcp = ikcp_create(6, NULL); c_kcp->output = c_udp_output; ikcp_nodelay(c_kcp, 1, 10, 0, 1);//可以收到图像 c_kcp->rx_minrto = 10; c_kcp->fastresend = 1; ikcp_wndsize(c_kcp, 128, 128); ikcp_setmtu(c_kcp, 1400);

    ikcp_update用定时器启动,我udp收到消息以后 ikcp_input=0,ikcp_recv一直等于-1,这个需要怎么处理, 我推流的 那端 用ikcp_waitsnd设置了最大的阀值,超过就不会再调用ikcp_send,求教

    opened by xhzth7091 7
  • Receiving a single message of size greater than (MTU - IKCP_OVERHEAD) * rcvwnd causes the receiver to get stuck forever

    Receiving a single message of size greater than (MTU - IKCP_OVERHEAD) * rcvwnd causes the receiver to get stuck forever

    I might have got some details wrong, but my understanding from reading the code is: ikcp_recv can only return a received message when all packets of the message have moved onto the receive queue. Since the receive queue is allowed to store at most rcvwnd packets, and each packet stores MTU - IKCP_OVERHEAD bytes of data, if you send a single message of size (MTU - IKCP_OVERHEAD) * rcvwnd bytes, the receiver will get stuck forever and never receive any more messages (while its receive buffer grows forever).

    I am working around this by setting the rcvwnd to 255, since a message is not allowed to be larger than 255 * (MTU - IKCP_OVERHEAD) bytes anyway, but it was quite surprising.

    opened by grandseiken 7
  • 关于cwnd的更新

    关于cwnd的更新

    请教一个问题:在ikcp_input中,最后进行了拥塞窗口的更新: if (_itimediff(kcp->snd_una, prev_una) > 0) { if (kcp->cwnd < kcp->rmt_wnd) { IUINT32 mss = kcp->mss; if (kcp->cwnd < kcp->ssthresh) { kcp->cwnd++; kcp->incr += mss; /* 可以发送的最大数据量 */ } else { if (kcp->incr < mss) kcp->incr = mss;

    			kcp->incr += (mss * mss) / kcp->incr + (mss / 16);
    
    			if ((kcp->cwnd + 1) * mss <= kcp->incr)
    			{
    			#if 1
    				kcp->cwnd = (kcp->incr + mss - 1) / ((mss > 0)? mss : 1);
    			#else
    				kcp->cwnd++;
    			#endif
    			}
    		}
    		if (kcp->cwnd > kcp->rmt_wnd) {
    			kcp->cwnd = kcp->rmt_wnd;
    			kcp->incr = kcp->rmt_wnd * mss;
    		}
    	}
    }
    

    这样的话,无论是本次确认了1个packet,还是确认了10个packet,cwnd的改变幅度都是一样的是吗? 另外,cwnd更新方法和tcp基本一致,但增加了一个mss/16项,这有什么意义吗,是不是这样在和TCP抢占的时候增加了几分优势?

    opened by chenhongquan 0
  • moon cat  I  will  look  for  you  all  the  time

    moon cat I will look for you all the time

    moon cat I will look for you all the time

    Originally posted by @huoxinglaoshu in https://github.com/skywind3000/kcp/issues/334#issuecomment-1054323872

    opened by siamesefeifei 4
Releases(1.7)
Owner
Linwei
Coding since 1991
Linwei
Lightway Core is a modern VPN protocol by ExpressVPN, to deliver a VPN experience that’s faster, more secure, and more reliable.

Lightway Core is a modern VPN protocol by ExpressVPN, to deliver a VPN experience that’s faster, more secure, and more reliable.

ExpressVPN 302 Jun 15, 2022
Simple and small reliable UDP networking library for games

libquicknet Simple and small reliable UDP networking library for games ❗ libquicknet is under development and not suitable for production code ❗ The m

null 23 May 12, 2022
ENet reliable UDP networking library

Please visit the ENet homepage at http://enet.bespin.org for installation and usage instructions. If you obtained this package from github, the quick

Lee Salzman 2.1k Jun 24, 2022
Reliable & unreliable messages over UDP. Robust message fragmentation & reassembly. P2P networking / NAT traversal. Encryption.

GameNetworkingSockets GameNetworkingSockets is a basic transport layer for games. The features are: Connection-oriented API (like TCP) ... but message

Valve Software 6.1k Jun 21, 2022
Data-oriented networking playground for the reliable UDP transports

NetDynamics is a data-oriented networking playground for the reliable UDP transports. The application was created for stress testing and debugging a p

Stanislav Denisov 88 Jun 20, 2022
This API uses both composition and inheritance to provide a generic way to set up a custom server with a custom communication protocol and custom middlewares

Ziapi Summary Introduction Installation Introduction This API uses both composition and inheritance to provide a generic way to set up a custom server

Aurélien Boch 8 Apr 22, 2022
Mongoose Embedded Web Server Library - a multi-protocol embedded networking library with TCP/UDP, HTTP, WebSocket, MQTT built-in protocols, async DNS resolver, and non-blocking API.

Mongoose - Embedded Web Server / Embedded Networking Library Mongoose is a networking library for C/C++. It implements event-driven non-blocking APIs

Cesanta Software 8.5k Jun 29, 2022
FreeRDP is a free remote desktop protocol library and clients

FreeRDP is a free implementation of the Remote Desktop Protocol (RDP), released under the Apache license. Enjoy the freedom of using your software wherever you want, the way you want it, in a world where interoperability can finally liberate your computing experience.

null 7k Jun 27, 2022
Winpcap-based network packet capture tool, support TLS (part), UDP, ICMP, TCP, ARP, DNS and other protocol analysis, interface reference wireshark.

Winpcap-based network packet capture tool, support TLS (part), UDP, ICMP, TCP, ARP, DNS and other protocol analysis, interface reference wireshark.

null 34 Jun 19, 2022
mvfst is a client and server implementation of IETF QUIC protocol in C++ by Facebook.

mvfst (Pronounced move fast) is a client and server implementation of IETF QUIC protocol in C++ by Facebook.

Meta Incubator 1.1k Jun 19, 2022
QuantumGate is a peer-to-peer (P2P) communications protocol, library and API written in C++.

About QuantumGate is a peer-to-peer (P2P) communications protocol, library and API. The long-term goal for QuantumGate is to become a platform for dis

Karel Donk 82 May 28, 2022
Portable, single-file, protocol-agnostic TCP and UDP socket wrapper, primarily for game networking

Documentation This is a header-only library, as such most of its functional documentation is contained within the "header section" of the source code

null 62 Mar 23, 2022
C and C++ client for QuestDB Input Line Protocol over TCP

c-questdb-client QuestDB - InfluxDB Line Protocol - Ingestion Client Library for C and C++ This library makes it easy to insert data into QuestDB. Thi

QuestDB 13 Jun 2, 2022
XQUIC Library released by Alibaba is a cross-platform implementation of QUIC and HTTP/3 protocol.

XQUIC 简体中文文档 README-zh-CN Introduction XQUIC Library released by Alibaba is … … a client and server implementation of QUIC and HTTP/3 as specified by

Alibaba 1.1k Jun 22, 2022
🤝 A simple and extensible boot protocol

_ _ _ | | | | | | | |__| | __ _ _ __ __| | _____ _____ _ __

Brutal 5 Jun 25, 2022
owfuzz: a WiFi protocol fuzzing tool using openwifi.

Openwifi is an open-source WiFi protocol stack based on SDR that is fully compatible with Linux mac80211. It's driver takes advantage of the Linux kernel's supports (mac80211, cfg80211) for WiFi high MAC, so it can provide an interface to the application layer like a common WiFi USB dongle.

Alipay 135 Jun 23, 2022
A Google Chat protocol plugin for libpurple/Pidgin/bitlbee/whatever

Google Chat Plugin for libpurple A WORK IN PROGRESS replacement prpl for Google Chat in Pidgin/libpurple to support the proprietary protocol that Goog

Eion Robb 61 Jun 15, 2022
An implementation of the Mobile Adapter GB protocol, to connect to custom game servers.

libmobile Library that implements the Mobile Adapter GB protocol, in a way that should be easy to integrate into a plethora of different emulators/har

REON Team 8 May 11, 2022
The implementation of the Domino Network protocol based program.

spacex The implementation of the Domino distributed storage network protocol for the Smart Ecology. With a fully featured and well documented that pro

DominoNetwork 4 Sep 26, 2021