Skip to content
Linwei edited this page May 23, 2018 · 17 revisions

最佳实践

内存分配器

默认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带来的浪费。

管理大规模连接

如果需要同时管理大规模的 KCP连接(比如大于3000个),比如你正在实现一套类 epoll的机制,那么为了避免每秒钟对每个连接调用大量的调用 ikcp_update,我们可以使用 ikcp_check 来大大减少 ikcp_update调用的次数。 ikcp_check返回值会告诉你需要在什么时间点再次调用 ikcp_update(如果中途没有 ikcp_send, ikcp_input的话,否则中途调用了 ikcp_send, ikcp_input的话,需要在下一次interval时调用 update)

标准顺序是每次调用了 ikcp_update后,使用 ikcp_check决定下次什么时间点再次调用 ikcp_update,而如果中途发生了 ikcp_send, ikcp_input 的话,在下一轮 interval 立马调用 ikcp_update和 ikcp_check。 使用该方法,原来在处理2000个 kcp连接且每 个连接每10ms调用一次update,改为 check机制后,cpu从 60%降低到 15%。

避免缓存积累延迟

不管是 TCP/KCP,信道能力在那里放着,让你没法无限制的调用 send,请阅读:“如何避免缓存积累延迟” 这篇 wiki。

协议栈分层组装

不要试图将任何加密或者 FEC相关代码实现到 KCP里面,请实现成不同协议单元并组装成你的协议栈,具体请看:协议栈分层组装

如何支持收发可靠和非可靠数据?

有的产品可能除了需要可靠数据,还需要发送非可靠数据,那么 KCP 如何支持这种需求呢?很简单,你自己实现:

connection.send(channel, pkt, size);

channel == 0 使用 kcp 发送可靠包,channel == 1 使用 udp 发送非可靠包。

因为传输是你自己实现的,你可以在发送UDP包的头部加一个字节,来代表这个 channel,收到远程来的 UDP以后,也可以判断 channel==0 的话,把剩下的数据给 ikcp_input,否则剩下的数据为远程非可靠包。

这样你得到了一个新的发送函数,用channel来区别你想发送可靠数据还是非可靠数据。再统一封装一个 connection.recv 函数,先去 ikcp_recv 那里尝试收包,收不到的话,看刚才有没有收到 channel=1 的裸UDP包,有的话返回给上层用户。

如果你的服务端是混用 tcp/udp 的话,你还可以设计个 channel=2 使用 TCP 发送数据,针对一些比较大的,延迟不敏感的东西。