KCP简介

KCP是一个快速可靠的协议,能以比 TCP浪费10%-20%的带宽的代价,换取平均延迟降低 30%-40%,且最大延迟降低三倍的传输效果。纯算法实现,并不负责底层协议(如UDP)的收发,需要使用者自己定义下层数据包的发送方式,以 callback的方式提供给 KCP。 连时钟都需要外部传递进来,内部不会有任何一次系统调用。

整个协议只有 ikcp.h, ikcp.c两个源文件,可以方便的集成到用户自己的协议栈中。也许你实现了一个P2P,或者某个基于 UDP的协议,而缺乏一套完善的ARQ可靠协议实现,那么简单的拷贝这两个文件到现有项目中,稍微编写两行代码,即可使用。

KCP特性

TCP是为流量设计的(每秒内可以传输多少KB的数据),讲究的是充分利用带宽。而 KCP是为流速设计的(单个数据包从一端发送到一端需要多少时间),以10%-20%带宽浪费的代价换取了比 TCP快30%-40%的传输速度。TCP信道是一条流速很慢,但每秒流量很大的大运河,而KCP是水流湍急的小激流。KCP有正常模式和快速模式两种,通过以下策略达到提高流速的结果:

  1. RTO翻倍vs不翻倍:
    TCP超时计算是RTOx2,这样连续丢三次包就变成RTOx8了,十分恐怖,而KCP启动快速模式后不x2,只是x1.5(实验证明1.5这个值相对比较好),提高了传输速度。
  2. 选择性重传 vs 全部重传:
    TCP丢包时会全部重传从丢的那个包开始以后的数据,KCP是选择性重传,只重传真正丢失的数据包。
  3. 快速重传:
    发送端发送了1,2,3,4,5几个包,然后收到远端的ACK: 1, 3, 4, 5,当收到ACK3时,KCP知道2被跳过1次,收到ACK4时,知道2被跳过了2次,此时可以认为2号丢失,不用等超时,直接重传2号包,大大改善了丢包时的传输速度。
  4. 延迟ACK vs 非延迟ACK:
    TCP为了充分利用带宽,延迟发送ACK(NODELAY都没用),这样超时计算会算出较大 RTT时间,延长了丢包时的判断过程。KCP的ACK是否延迟发送可以调节。
  5. UNA vs ACK+UNA:
    ARQ模型响应有两种,UNA(此编号前所有包已收到,如TCP)和ACK(该编号包已收到),光用UNA将导致全部重传,光用ACK则丢失成本太高,以往协议都是二选其一,而 KCP协议中,除去单独的 ACK包外,所有包都有UNA信息。
  6. 非退让流控:
    KCP正常模式同TCP一样使用公平退让法则,即发送窗口大小由:发送缓存大小、接收端剩余接收缓存大小、丢包退让及慢启动这四要素决定。但传送及时性要求很高的小数据时,可选择通过配置跳过后两步,仅用前两项来控制发送频率。以牺牲部分公平性及带宽利用率之代价,换取了开着BT都能流畅传输的效果。

KCP与TCP

TCP与UDP都是传输层的协议,比较两者的区别主要应该是说TCP比UDP多了什么?

  • 面向连接:TCP接收方与发送方维持了一个状态(建立连接,断开连接),双方知道对方还在。
  • 可靠的:发送出去的数据对方一定能够接收到,而且是按照发送的顺序收到的。
  • 流量控制与拥塞控制:TCP靠谱通过滑动窗口确保,发送的数据接收方来得及收。TCP无私,发生数据包丢失的时候认为整个网络比较堵,自己放慢数据发送速度。

TCP协议的可靠与无私让使用TCP开发更为简单,同时它的这种设计也导致了慢的特点。UDP协议简单,所以它更快。但是,UDP毕竟是不可靠的,应用层收到的数据可能是缺失、乱序的。

KCP协议就是在保留UDP快的基础上,提供可靠的传输,应用层使用更加简单。TCP可靠简单,但是复杂无私,所以速度慢。KCP尽可能保留UDP快的特点下,保证可靠。

使用方式

1. 创建 KCP对象:

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

2. 设置传输回调函数(如UDP的send函数):

// 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收到的数据包):

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

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

协议配置

协议默认模式是一个标准的 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是一个可靠的传输协议,UDP本身是不可靠的,所以需要额外信息来保证传输数据的可靠性。因此,我们需要在传输的数据上增加一个包头。用于确保数据的可靠、有序。

0                         4      5     6      8 (BYTE)+-------------------+----+----+----+ |      conv      | cmd | frg |  wnd | +-------------------+----+----+----+   8|         ts         |             sn           | +-------------------+----------------+  16|       una       |             len          |+-------------------+----------------+   24|                                                   ||            DATA (optional)          ||                                                   |+-------------------------------------+
  • conv:连接号。UDP是无连接的,conv用于表示来自于哪个客户端。对连接的一种替代
  • cmd:命令字。如,IKCP_CMD_ACK确认命令,IKCP_CMD_WASK接收窗口大小询问命令,IKCP_CMD_WINS接收窗口大小告知命令
  • frg:分片,用户数据可能会被分成多个KCP包,发送出去
  • wnd:接收窗口大小,发送方的发送窗口不能超过接收方给出的数值 ts:时间序列
  • sn:序列号
  • una:下一个可接收的序列号。其实就是确认号,收到sn=10的包,una为11
  • len:数据长度
  • data:用户数据

讲解主要以极速模式: ikcp_nodelay(kcp, 1, 10, 2, 1)为主,启用nodelay设置,刷新间隔控制在10ms,开启快速重传模式,关闭流量控制。

数据发送过程

用户发送数据的函数为ikcp_send。ikcp_send(ikcpcb kcp, const char buffer, int len)。该函数的功能非常简单,把用户发送的数据根据MSS进行分片。放入到名为snd_queue的待发送队列中。

注:流模式情况下,kcp会把两次发送的数据衔接为一个完整的kcp包。非流模式下,用户数据%MSS的包,也会作为一个包发送出去。

MTU,数据链路层规定的每一帧的最大长度,超过这个长度数据会被分片。通常MTU的长度为1500字节,IP协议规定所有的路由器均应该能够转发(512数据+60IP首部+4预留=576字节)的数据。

MSS,最大输出大小(双方的约定),KCP的大小为MTU-kcp头24字节。IP数据报越短,路由器转发越快,但是资源利用率越低。传输链路上的所有MTU都一至的情况下效率最高,应该尽可能的避免数据传输的工程中,再次被分。UDP再次被分的后(通常1分为2),只要丢失其中的任意一份,两份都要重新传输。因此,合理的MTU应该是保证数据不被再分的前提下,尽可能的大。

以太网的MTU通常为1500字节-IP头(20字节固定+40字节可选)-UDP头8个字节=1472字节。KCP会考虑多传输协议,但是在UDP的情况下,设置为1472字节更为合理。

实际发送

KCP会不停的进行update更新最新情况,数据的实际发送在update时进行。发送过程如下图所示:

  • 待发送队列移至发送队列
    KCP会把snd_queue待发送队列中的kcp包,移至snd_buf发送队列。移动的包的数量不会超过snd_una+cwnd-snd_nxt,确保发送的数据不会让接收方的接收队列溢出。该功能类似于TCP协议中的滑动窗口。cwnd=min(snd_wnd,rmt_wnd,kcp->cwnd)的最小值决定,snd_wnd,rmt_wnd比较好理解可发送的数据,可发送的数据最大值,应该是发送方可以发送的数据和接收方可以接收的数据的最小值。kcp->cwnd是拥塞控制的一个值,跟网络状况相关,网络状况差的时候,KCP认为应该降低发送的数据,后面会有详细的介绍。

    如上图中,snd_queue待发送队列中有4个KCP包等待发送,这个时候snd_nxt下一个发送的kcp包序列号为11,snd_una下一个确认的KCP包为9(8已经确认,9,10已经发送但是还没得到接收方的确认)。因为cwnd=5,发送队列中还有2个发送了但是还未得到确认,所以可以从待发送队列中取前面的3个KCP包放入到发送队列中,序列号分别设置为11,12,13。

  • 发送发送队列的数据

    发送队列中包含两种类型的数据,已发送但是尚未被接收方确认的数据,没被发送过的数据。没发送过的数据比较好处理,直接发送即可。重点在于已经发送了但是还没被接收方确认的数据,该部分的策略直接决定着协议快速、高效与否。KCP主要使用两种策略来决定是否需要重传KCP数据包,超时重传、快速重传、选择重传。

  • 超时重传

TCP超时计算是RTOx2,这样连续丢三次包就变成RTOx8了,而KCP非快速模式下每次+RTO,急速模式下+0.5RTO(实验证明1.5这个值相对比较好),提高了传输速度。

  • 快速重传

发送端发送了1,2,3,4,5几个包,然后收到远端的ACK: 1, 3, 4, 5,当收到ACK3时,KCP知道2被跳过1次,收到ACK4时,知道2被跳过了2次,此时可以认为2号丢失,不用等超时,直接重传2号包,大大改善了丢包时的传输速度。TCP有快速重传算法,TCP包被跳过3次之后会进行重传。
注:可以通过统计错误重传(重传的包实际没丢,仅乱序),优化该设置。

  • 选择重传

老的TCP丢包时会全部重传从丢的那个包开始以后的数据,KCP是选择性重传,只重传真正丢失的数据包。但是,目前大部分的操作系统,linux与android手机均是支持SACK选择重传的。

  • 数据发送

通过判定,kcp包是否需要发送,如果需要发送的kcp包则通过,kcp_setoutput设置的发送接口进行发送,UDP通常为sendto。步骤3,会对较小的kcp包进行合并,一次性发送提高效率

KCP-快速的可靠网络传输协议相关推荐

  1. 快速可靠网络传输协议 KCP

    KCP 是一个快速可靠协议,能以比 TCP浪费10%-20%的带宽的代价,换取平均延迟降低30%-40%,且最大延迟降低三倍的传输效果.纯算法实现,并不负责底层协议(如UDP)的收发,需要使用者自己定 ...

  2. 几种常见的可靠UDP传输协议(包含C#实现)

    几种UDP网络库的整理Raknet,UDT,ENet,lidgren-network-gen3 http://blog.csdn.net/u014630768/article/details/3489 ...

  3. 《计算机网络自顶向下》 Miscellaneous Lab1 Implementing a Reliable Transport Protocol(实现可靠的传输协议(上))

    文章目录 前引 Lab1 实现可靠的传输协议 Lab1 文档查阅(友情提供下载链接) 查看c语言参数声明的说明 原模版代码(个人整理格式后) 原模板代码(稍加分析) 交替位协议版本 代码实现 交替位协 ...

  4. protobuf网络传输协议的优缺点

    为什么使用protobuf? protobuf常使用于作为C/S之间的数据传输的序列化工具,可以使用protobuf实现rpc框架的通信传输. 对于App网络传输协议,我们比较常见的.可选的,有三种, ...

  5. ajax,HTTP原理 : 网络传输协议,网页从输入url到渲染的流程,函数防抖和节流

    一. 前后端交互流程 1.服务器 : 提供某种服务器的机器(计算机) qq音乐:音频服务器 , 迅雷:文件服务器 , qq邮箱:邮件服务器,爱奇艺:视频服务器,谷歌:web服务器 2. 前端 访问 服 ...

  6. 网络传输协议概念和HTTP协议

    网络传输协议概念 网络传输协议或简称为传送协议,是指计算机通信或网络设备的共同语言.现在最普及的计算机通信为网络通信,所以"传送协议"一般都指计算机通信的传送协议,如:TCP/IP ...

  7. php上传报文,PHP-02.文件上传、php保存/转移上传的文件、常见的网络传输协议、请求报文及属性、响应报文及属性...

    关系数组 array("key"=>"value",...) ; get没有数据大小的限制 post上传大小没有限制 不指定上传方式,默认是get 文件上 ...

  8. PHP-02.文件上传、php保存/转移上传的文件、常见的网络传输协议、请求报文及属性、响应报文及属性...

    关系数组 array("key"=>"value",...) ; get没有数据大小的限制 post上传大小没有限制 不指定上传方式,默认是get 文件上 ...

  9. ProtoBuf(protocol buffer) 网络传输协议

    ProtoBuf(protocol buffer) 网络传输协议 转自:http://blog.csdn.net/wenyiqingnianiii/article/details/52741312 P ...

最新文章

  1. UpSetR 高级参数使用教程
  2. SAP MM 外部采购流程里的Advanced Return Management
  3. 如何用手机打开dcm格式图片_手机也能当扫描仪用?如何用手机扫描图片?
  4. runtime-归档
  5. 数字电路实验怎么接线视频讲解_家庭影院中音箱、功放、投影机、4K播放机不知道怎么连接?手把手教你...
  6. python 删除csv第一行_python 标准库学习之 csv
  7. 你的搜索其实很糟糕?
  8. java国际规范标准,国际化 - Java Servlet 3.1 规范
  9. dtmf信号系统的matlab仿真,dtmf信号系统的matlab仿真毕业设计
  10. 区块链 以太坊 每个区块可以包含多少个交易
  11. 学生宿舍管理信息系统软件测试,asp.net学生宿舍管理系统
  12. VASP学习记录与总结
  13. 看拉扎维《模拟CMOS集成电路设计》的一些总结和思考(五)——无源与有源电流镜
  14. bp神经网络java代码_BP神经网络的Java实现
  15. iTextSharp显示中文
  16. python程序设计从基础到开发课后题答案夏敏捷_Python程序设计——从基础到开发...
  17. 【51单片机】按键控制多个舵机(可用于机械臂控制)
  18. H5游戏营销如何入手,最经典h5游戏案例盘点
  19. 场景式营销——新商业时代的生存法则
  20. 流利阅读 2019.2.22 Duke University apologizes over professor’s email asking Chinese students to speak En

热门文章

  1. oracle vm 鼠标切换,VirtualBox的Linux虚拟机文本模式和图形模式的切换问题
  2. 1秒生成证件照——小米云证件照微信小程序
  3. 【Unity步步升】各类旋转逻辑的区别,如欧拉旋转、插值旋转、矢量朝向等...及游戏视角案例
  4. 按键扫描——74HC164驱动(一)
  5. ProPresenter 6 for Mac破解版永久激活方法
  6. 越努力,越幸运—2021年终总结
  7. 如何用地推进行有效获客降低成本提高效率?
  8. 1分钟利用Excel快速制作随机点名器
  9. 什么是JAVA?JAVA能用来干什么?
  10. chrome安装插件,安装Postman