mKCP

V2Ray 从 1.17 开始加入了一种新的流式传输协议 mKCP (modified KCP),用于克服传统的 TCP 在某些场景下的不足之处。 mKCP 在 KCP 协议的基础上进行了一些改进,可以无缝替换 TCP。

在此感谢:

  • @skywind3000 发明并实现了 KCP 协议;
  • @xtaci 将 KCP 由 C 语言实现翻译成 Go;
  • @xiaokangwang 测试 KCP 与 V2Ray 的整合并提交了最初的 PR。

对 KCP 协议的改进

更小的协议头

原生 KCP 协议使用了 24 字节的固定头部,而 mKCP 修改为数据包 18 字节,确认(ACK)包 16 字节。更小的头部有助于躲避特征检查,并加快传输速度。

另外,原生 KCP 的单个确认包只能确认一个数据包已收到,也就是说当 KCP 需要确认 100 个数据已收到时,它会发出 24 * 100 = 2400 字节的数据。其中包含了大量重复的头部数据,造成带宽的浪费。mKCP 会对多个确认包进行压缩,100 个确认包只需要 16 + 2 + 100 * 4 = 418 字节,相当于原生的六分之一。

确认包重传

原生 KCP 协议的确认(ACK)包只发送一次,如果确认包丢失,则一定会导致数据重传,造成不必要的带宽浪费。而 mKCP 会以一定的频率重发确认包,直到发送方确认为止。单个确认包的大小为 22 字节,相比起数据包的 1000 字节以上,重传确认包的代价要小得多。

连接状态控制

mKCP 可以有效地开启和关闭连接。当远程主机主动关闭连接时,连接会在两秒钟之内释放;当远程主机断线时,连接会在最多 30 秒内释放。

原生 KCP 不支持这个场景。

使用方式

KCP 的开启方式如下:

  • 在 Inbound 和 Outbound 配置中添加 streamSettings 并设置 network 为 "kcp"。
  • V2Ray 连接两端的 Inbound 和 Outbound 需要同时设置 kcp,否则无法连通。如果服务器端使用了动态端口,也需要指定 kcp。
"inbound": {
  "port": 8888,
  "protocol": "vmess",
  "settings": {}, // 略
  "streamSettings": {
    "network": "kcp" // 可选的值有 "kcp" 和 "tcp"
  }
}

调试建议

以下内容介绍了客户端从服务器下载数据的场景,上传的场景正好相反。

  • 客户端 kcpSettings 中的 downlinkCapacity 限制了客户端接收数据的速度;服务器端的 uplinkCapacity 限制了服务器发送数据的速度;两者中值小的那个决定了下载过程中的最大速度。
  • 建议把客户端的 downlinkCapacity 设置为了一个较大的值,如 100。也就是说,无论服务器端发来多少数据,客户端照单全收。而使用服务器端的 uplinkCapacity 来调节传输速度。
  • 假设带宽为 100 Mbps,可以将服务器端的 uplinkCapacity 设置为 100 / 8 = 12。理论上这个值已经可以用满带宽,但取决于实际的网络环境,可以略微上调 uplinkCapacity 的值,直到达到满意的速度。
  • 如果你的宽带速度不稳定,可以开启拥塞控制来让 V2Ray 动态调整发送数据的速度。

需要注意的问题:

  • 新的协议使用 UDP 进行传输,请确保防火墙设置正确;
  • KCP 牺牲带宽来降低延迟。传输同样的内容,KCP 一般比 TCP 消耗更多的流量;