kcp简介

  • Post author:
  • Post category:其他


kcp可以理解为可靠的udp协议。udp是面向无连接的协议,由于其实时性较好,通常用于游戏或音视频通话中,同时由于其不需要提前建立连接,能节省设备资源,也广泛应用于嵌入式设备中。另外,对于大量的数据传输如下载文件等场景,以及DNS中客户端请求域名对应的地址这个环节中,使用的是udp。注意,DNS另一部分,域名服务器节点之间的数据同步用的是tcp。

为了提高udp可靠性,在udp协议上封装一层可靠性传输机制(类似tcp的ACK机制、重传机制、序号机制、重排机制、窗口机制),就做到了兼具tcp的安全性(流量控制和拥塞控制等)和udp的实时性,并且具备一定的灵活性(超时重传、ack等),其中一个代表是kcp协议。



kcp协议头

kcp以10%-20%带宽浪费的代价换取了比 tcp快30%-40%的传输速度。kcp头部共24字节。

在这里插入图片描述

conv:连接号。UDP是无连接的,conv用于表示来自于哪个客户端,是对连接的一种替代。

cmd:命令字。如,IKCP_CMD_ACK确认命令,IKCP_CMD_WASK接收窗口大小询问命令,IKCP_CMD_WINS接收窗口大小告知命令。

frg:分片,用户数据可能会被分成多个KCP包,发送出去。

wnd:接收窗口大小,发送方的发送窗口不能超过接收方给出的数值。

ts:时间戳。

sn:序列号。

una:下一个可接收的序列号。其实就是确认号,类似tcp的ack。

len:数据长度。

data:用户数据。



kcp流程

注意收发数据时,数据要先放到缓存重排然后再进行收发。



数据接收

在这里插入图片描述

接收数据时,kcp会先把数据放到rcv_buf中进行缓存,注意rcv_buf中的数据是已经按sn排好序的,但是不一定完整连续,因为传输过程中可能有丢失,rcv_queue是从rcv_buf中拷贝出的连续完整的数据分片。用户调用ikcp_recv()时是从rcv_que中读取数据。还要注意一点,ikcp_recv中的len一定要是整个数据的长度,要一次性读完,这和recvfrom的size是一样的。



数据发送

在这里插入图片描述

与接收过程类似,只不过顺序相反,用户调用ikcp_send()只是将数据放到了snd_buf中,不过会自动进行数据分片,使得数据大小不超过mtu。然后,kcp会通过流量控制和拥塞控制将数据放到snd_buf中再进行发送。

注意区分一下,不断调用ikcp_send(),数据会累积在snd_queue中,如果对方没有接收,对方的数据则会累积在对方的rcv_buf中。

说了这么多,其实kcp底层调用的,还是recvfrom()和sendto(),这一点不要忘记。



kcp确认机制

snd_buf中存放的是已发送但未收到对方ack的数据包和未发送但可发送的数据包,如果收到了ack,相应的数据就会从snd_buf中删除。如上图中,8包已收到ack,从snd_buf删除,9、10包已发送但未收到ack。这里提一下,kcp的确认机制有两种,一种是una,与tcp的ack类似,代表una之前的包全部收到;还有一种是单独ack,只对某一个单独的包进行确认。kcp优先检测una。



kcp重传机制

kcp的重传机制体现了其较于tcp而言,灵活的地方。一是超时重传时间,可以自己设置,tcp是超时一次就将RTO×2,kcp可以×1.5,缩短了重传等待时间;二是建立了快速重传机制,如果一个数据包之后的指定个数据包已收到ack,那么即便未到该包的rto,也立即重传。取3包未收到ack,而4包和5包已经收到了ack,如果指定的是跳过2个包就认为包丢失,那么此时3包就立即重传,无论是否经过了3包的RTO。此外,kcp还可以选择是否设置延迟ack,超时只重传丢失包,采用非退让流控等,这些都使kcp的传输效率得以提高。

由于源码较长,这里就不贴出具体的代码了。当然,如果不熟悉kcp的源码,还建议不要使用kcp。



版权声明:本文为m0_65931372原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。