KCP协议浅析
概述
KCP协议结合了TCP和UDP协议的特点,是一个快速可靠的协议。
引述官方介绍:
KCP是一个快速可靠协议,能以比 TCP浪费10%-20%的带宽的代价,换取平均延迟降低 30%-40%,且最大延迟降低三倍的传输效果。纯算法实现,并不负责底层协议(如UDP)的收发,需要使用者自己定义下层数据的发送方式,以 callback的方式提供给 KCP。连时钟都需要外部传递进来,内部不会有任何一次系统调用。
TCP是为流量设计的(每秒内可以传输多少KB的数据),讲究的是充分利用带宽。而 KCP是为流速设计的(单个数据从一端发送到一端需要多少时间),以10%-20%带宽浪费的代价换取了比 TCP快30%-40%的传输速度。
传统的TCP/UDP协议见参考链接。
协议格式
| 4bit conv | 1bit cmd | 1bit frg | 2bit wnd |
| 4bit ts | 4bit sn |
| 4bit una | 4bit len |
| anybit 数据 |
- conv:会话序号,通信双方一致
- cmd:报文类型
- IKCP_CMD_ACK 确认
- IKCP_CMD_PUSH 数据推送
- IKCP_CMD_WASK 接收窗口查询大小
- IKCP_CMD_WINS 接收窗口大小告知
- wnd: 己方可用接收窗口大小,接收窗口大小 - 接收队列大小
- frg:包分片(数量)
- sn: 包分片序号
- ts: 时间戳,用于计算RTO和RTT
- una:待接收的序列号(确认号),表示该序列号之前的所有报文都收到了,可以删除
- len:用户数据长度
- 数据:用户数据
特点
RTO不翻倍
RTO(Retransmission-TimeOut)即重传超时时间,TCP和KCP是基于ARQ协议实现的可靠性,但TCP的超时计算是RTO2,而KCP的超时计算是RTO1.5,也就是说假如连续丢包3次,TCP是RTO8,而KCP则是RTO3.375,意味着可以更快地重新传输数据。
选择性重传
tcp 丢包时会全部重传从该包开始以后的数据,而 kcp 选择性重传,只重传真正丢失的数据包。
快速重传
收到fastresend(配置)个失序报文后,不等待超时,直接重传,减少丢包等待时间。
而TCP重传模式:
- 超时重传:超过规定的时间 RTO 则重传
- 快速重传:收到三个冗余ACK,不去等待 RTO ,直接重传
与TCP相同,都是通过累计确认实现的,发送端发送了1,2,3,4,5几个包,然后收到远端的ACK:1,3,4,5,当收到ACK = 3时,KCP知道2被跳过1次,收到ACK = 4时,知道2被跳过了2次,此时可以认为2号丢失,不用等超时,直接重传2号包,大大改善了丢包时的传输速度。
非延迟 ACK
停等ARQ协议
- A会为每个即将发送的数据编号,编号的目的是为了标识数据和给数据排序
- A发送完数据之后,会给这次发送的数据设置一个超时计时器
- B收到数据,将会返回一个确认,该确认也有自己的编号
- A收到确认,将删除副本且取消超时计时器,保留副本的原因是传输可能出错
- B收到错误的数据,或者数据在传输过程中出错,总之就是说B没有收到想要的数据
- A在超时计时器的设置时间内没有收到确认,此时重发数据
所以可靠的TCP有32位序列号和32位确认号,TCP和UDP都有16位校验和。
连续ARQ协议
连续ARQ协议不会响应每个数据段,而是仅仅响应编号最大的这个数据段,表示之前的数据都收到了,这个叫做UNA模式,而停等ARQ协议可以看作是ACK模式
ACK + UNA
ARQ (自动重传请求,Automatic Repeat-reQuest)模型响应有两种方式:
- UNA:此编号前所有包已收到
- ACK:该编号包已收到
只用 UNA 将导致全部重传,只用 ACK 则丢失成本太高,以往协议都是二选其一。而 kcp 协议中,除去单独的 ACK 包(精确)外,所有包都有 UNA 信息
非退让流控
KCP正常模式同TCP一样使用公平退让法则,即发送窗口大小由:发送缓存大小、接收端剩余接收缓存大小、丢包退让、慢启动这四要素决定,慢启动是在刚开始发送数据时让窗口缓慢扩张,退半避让是在网络拥堵时窗口大小减半,快重传是在网络恢复时及时给予响应,与之配合的就是快恢复。但传送及时性要求很高的小数据时,可选择仅用前两项来控制发送频率。以牺牲部分公平性及带宽利用率之代价,换取了流畅传输的效果。KCP 实时性好,但带宽利用率较低,因为:
- 非退让流控,不断尝试发送数据,有效包不多
- 每个包应答,占用一定的带宽
窗口协议中有两种:
- 拥塞窗口:防止过多的数据注入到网络中,这样可以使网络中的路由器 和链路不至于过载。
- 滑动窗口:接收方告知发送方自己可以接收缓冲区的大小,通常与连续ARQ协议配合使用。
结构
大概流程如图示,若是想深入探索底层实现,请参考源码或者参考链接中的详解