17 KCP Best Practice
Linwei edited this page 2018-05-23 18:26:35 +08:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

最佳实践

内存分配器

默认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 发送数据,针对一些比较大的,延迟不敏感的东西。