unity接入kcp

unity接入kcp

一.前言

KCP是一种基于UDP的上层协议,项目地址:KCP – A Fast and Reliable ARQ Protocol,以下是github上的介绍:

KCP是一个快速可靠协议,能以比 TCP浪费10%-20%的带宽的代价,换取平均延迟降低 30%-40%,且最大延迟降低三倍的传输效果。纯算法实现,并不负责底层协议(如UDP)的收发,需要使用者自己定义下层数据包的发送方式,以 callback的方式提供给 KCP。 连时钟都需要外部传递进来,内部不会有任何一次系统调用。

整个协议只有 ikcp.h, ikcp.c两个源文件,可以方便的集成到用户自己的协议栈中。也许你实现了一个P2P,或者某个基于 UDP的协议,而缺乏一套完善的ARQ可靠协议实现,那么简单的拷贝这两个文件到现有项目中,稍微编写两行代码,即可使用。

简单来说,kcp就是在udp上再做了一层封装,来实现TCP的效果并且弥补TCP的一些不足。使用kcp的方式就是和服务器连接一个udp连接,然后再udp的通信过程中,使用kcp库对字节进行处理。然后通过kcp拿到数据包。kcp可以保证你拿到的包,一,不会丢包,二,保证数据包的发送顺序和接收顺序一致。这其实就是tcp的功能。但是kcp的速度比tcp要快的多。

二.kcp的原理

下面是简单说一下kcp的原理:

kcp其实就是我们常说的协议,比如tcp协议,http协议,那么kcp需要遵循哪些条款呢?

KCP的帧头结构

KCP帧头8字节对齐,KCP空包大小为24字节。

+-------+-------+-------+-------+-------+-------+-------+-------+
|             conv              |  cmd  |  frg  |      wnd      |
+-------+-------+-------+-------+-------+-------+-------+-------+
|               ts              |               sn              |
+-------+-------+-------+-------+-------+-------+-------+-------+
|               una             |               len             |
+-------+-------+-------+-------+-------+-------+-------+-------+
|                                                               |
*                              data                             *
|                                                               |
+-------+-------+-------+-------+-------+-------+-------+-------+

conv(conversation)

4字节,会话标识。

我们知道UDP不是面向连接的,因此KCP自己实现了一套会话机制。conv由客户端connect时随机生成的,之后客户端和服务端交互均使用这个一致的conv值,以此来标识两个peer之间的通信是一个会话。不同客户端的conv值互相不影响,相不相同对服务器都没有影响。

cmd(command)

1字节,是标识KCP包的功能。有以下几种:

  • IKCP_CMD_PUSH = 81 // cmd: push data
  • IKCP_CMD_ACK = 82 // cmd: ack
  • IKCP_CMD_WASK = 83 // cmd: window probe (ask)
  • IKCP_CMD_WINS = 84 // cmd: window size (tell)

frg(fragment)

1字节,分段序号。

KCP有两种模式,一种是stream模式,一种是message模式。当为stream模式时,frg的值始终为0。当为message模式时,传输的数据大小超过MTU限制,会被分成多个包,通过frg来标识不同包的序号,使得在不知道包到达的先后顺序的情况下也能够通过frg字段来重新按照顺序组装成原始数据。

NOTE:在使用kcp-go库的时候,会在写入KCP之前进行分包操作,因此无论数据多大,frg的值始终为0。~~至于库作者为什么这么做,暂时不清楚。~~这样会更安全一些,否则发送一个超大的包,在KCP core内部进行分包时,包的数量可能大于255,而frg为固定1字节长,因此会出错,为了避免发生这样的错误,提前做了分包操作。

wnd

1字节,窗口大小,自己(发送当前包的peer)能够接收数据量。

窗口大小可以为0,当为0时,在发送数据前会进行探测窗口大小的操作。

ts

4字节,当前毫秒时间戳。

sn

4字节,包序号。

该包序号为当前会话中的序号,从0开始。

una

4字节,此编号前所有的包都已收到。

ARQ模型响应有两种,UNA(此编号前所有包已收到,如TCP)和ACK(该编号包已收到),光用UNA将导致全部重传,光用ACK则丢失成本太高,以往协议都是二选其一,而 KCP协议中,除去单独的 ACK包外,所有包都有UNA信息。

len

4字节,数据部分的长度。所以使用kcp的话就 不用必须自己封包时添加字节长度了。

三.KCP CSharp

unity接入kcp的话,肯定要c#版本的,但是同样是c#版本kcp,也是有区别的,

第一种方式:c#移植版

移植版,就是使用c#语言翻译原版c的kcp库。一般这样实现的库有很多,但是质量参差不齐,有的是完美移植,有的可能会遗留一些问题,比如gc太多等

目前用的还比较多的有:

  • kcp-csharp: kcp的 csharp移植,同时包含一份回话管理,可以连接上面kcp-go的服务端,且和kcp-go的语法相似。
  • kcp-csharp: 新版本 Kcp的 csharp移植。线程安全,运行时无alloc,对gc无压力。

第二种方式:动态库版

动态库版,就是把原版c的kcp库,进行动态库编译,编译为ios,android,pc,linux等平台的库,然后我们使用C#去封装一个udp,然后调用kcp的动态链接库。

这种方式,好处是可以保留原版库的所有特性,不用考虑优化语法的问题了,而且性能比较好。但是坏处就是编译动态库较麻烦,需要针对所有平台…可想而知

动态链接库的编译,请参考
unity3d构建kcp跨平台动态链接库

我根据ET框架的网络框架,简化了其中的代码结构,删除了server部分,tcp和kcp都可以直接与服务器对接,服务器支持任何语言,其中go和java都已经测试通过

代码仓库https://github.com/passiony/kcp-unity

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页
实付 19.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值