传统游戏项目一般使用TCP协议进行通信,得益于它的稳定和可靠,不过在网络不稳定的情况下,会出现丢包严重 。
不过近期有不少基于UDP的应用层协议,声称对UDP的不可靠进行了改造,这意味着我们既可以享受网络层提供稳定可靠的服务,又可以享受它的速度 。
KCP就是这样的一个协议
不过网上说的再天花乱坠,我们也得亲自调研,分析源码和它的机制,并测试它的性能,是否满足项目上线要求 。本文从C版本的源码入手理解KCP的机制,再研究各种JAVA版本的实现
一、KCP协议原版源码(C代码):
https://github.com/skywind3000/kcp
基于底层协议(一般是UDP)之上,完全在应用层实现类TCP的可靠机制(快速重传,拥塞控制等)
二、KCP特性KCP实现以下特性,也可参考github中README中对KCP的定义
说明
源码位置
RTO优化
超时时间计算优于TCP
ikcp_update_ack
选择性重传
KCP只重传真正丢失的数据包,TCP会全部重传丢失包之后的全部数据
ikcp_parse_fastack,ikcp_flush
快速重传
根据配置,可以在丢失包被跳过一定次数后直接重传,不等RTO超时
ikcp_parse_fastack,ikcp_flush
UNA + ACK
ARQ模型响应有两种,UNA(此编号前所有包已收到,如TCP),ACK(该编号包已收到),光用UNA将导致全部重传,光用ACK则丢失成本太高,以往协议都是二选其一,而 KCP协议中,除去单独的 ACK包外,所有包都有UNA信息 。
ikcp_flush(每次update,都发送ACK)
非延迟ACK
KCP可配置是否延迟发送ACK
ikcp_update_ack
流量控制
同TCP的公平退让原则,发送窗口大小由:发送缓存大小、接收端剩余接收缓存大小、丢包退让及慢启动这四要素决定
ikcp_input,
ikcp_flush
三、KCP报文1. 报文解析源码源码中对报文解析部分代码如下
data = https://www.isolves.com/sj/zs/2021-12-23/ikcp_decode32u(data, &conv);if (conv != kcp->conv) return -1;data = ikcp_decode8u(data, &cmd);data = ikcp_decode8u(data, &frg);data = ikcp_decode16u(data, &wnd);data = ikcp_decode32u(data, &ts);data = ikcp_decode32u(data, &sn);data = ikcp_decode32u(data, &una);data = ikcp_decode32u(data, &len);2. 报文定义报文中标识的定义全称
备注
作用
conv
conversation id
会话ID
每个连接的唯一标识
cmd
command
命令
每个数据包指定逻辑
frg
fragment count
数据分段序号
根据mtu(最大传输单元)和mss(最大报文长度)的数据分段
wnd
window size
接收窗口大小
流量控制
ts
timestamp
时间戳
数据包发送时间记录
sn
serial number
数据报的序号
确保包的有序
una
un-acknowledged serial number
对端下一个要接收的数据报序号
确保包的有序
3. 消息类型KCP报文的四种消息类型
const IUINT32 IKCP_CMD_PUSH = 81;// cmd: push data: 推送数据const IUINT32 IKCP_CMD_ACK= 82;// cmd: ack: 对推送数据的确认const IUINT32 IKCP_CMD_WASK = 83;// cmd: window probe (ask): 询问窗口大小const IUINT32 IKCP_CMD_WINS = 84;// cmd: window size (tell): 回复窗口大小- 报文结构

文章插图
四、源码解析在网络四层模型中,KCP和TCP/UDP(传输层),IP(网络层)等协议有着本质上区别,理论上KCP是属于应用层协议 。
KCP并不提供协议实际收发处理,它只是在传输层只上对消息和链接的一层中间管理 。
在KCP的源码中,它仅仅包含ikcp.c和ikcp.h两个文件,仅提供KCP的数据管理和数据接口,而用户需要在应用层进行KCP的调度
1. 结构体定义KCP分包结构KCP对象结构体定义
struct IKCPSEG{struct IQUEUEHEAD node;IUINT32 conv; //用来标记这个seg属于哪个kcpIUINT32 cmd;//这个包的指令是: // 数据 ack 询问/应答窗口大小IUINT32 frg; //分包时,分包的序号,0为终结IUINT32 wnd;//发送这个seg的这个端的 窗口大小--> 远端的接收窗口大小IUINT32 ts; //我不知道为什么要用时间轴,这个都1秒,有什么用 ??IUINT32 sn;//相当于tcp的ackIUINT32 una;//una 远端等待接收的一个序号IUINT32 len; //data的长度IUINT32 resendts;//重发的时间轴IUINT32 rto;//等于发送端kcp的 rx_rto->由 计算得来IUINT32 fastack;//ack跳过的次数,用于快速重传IUINT32 xmit;// fastack resend次数char data[1];//当malloc时,只需要malloc(sizeof(IKCPSEG)+datalen) 则,data长=数据长度+1 刚好用来放0};struct IKCPCB{//会话ID,最大传输单元,最大分片大小,状态mss=mtu-sizeof(IKCPSEG)IUINT32 conv, mtu, mss, state;//第一个未接收到的包,待发送的包(可以认为是tcp的ack自增),接收消息的序号-> 用来赋seg的una值IUINT32 snd_una, snd_nxt, rcv_nxt;//前两个不知道干嘛拥塞窗口的阈值 用来控制cwnd值变化的IUINT32 ts_recent, ts_lastack, ssthresh;//这几个变量是用来更新rto的// rx_rttval 接收ack的浮动值// rx_srtt 接收ack的平滑值// rx_rto 计算出来的rto// rx_minrto 最小rtoIINT32 rx_rttval, rx_srtt, rx_rto, rx_minrto;//发送队列的窗口大小//接收队列的窗口大小//远端的接收队列的窗口大小//窗口大小//probe 用来二进制标记IUINT32 snd_wnd, rcv_wnd, rmt_wnd, cwnd, probe;//时间轴 时间间隔 下一次flush的时间xmit发射多少次? 看不到有什么地方用到IUINT32 current, interval, ts_flush, xmit;//接收到的数据seg个数//需要发送的seg个数IUINT32 nrcv_buf, nsnd_buf;//接收队列的数据 seg个数//发送队列的数据 seg个数IUINT32 nrcv_que, nsnd_que;//是否为nodelay模式:如果开启,rto计算范围更小//updated 在调用flush时,有没有调用过updateIUINT32 nodelay, updated;//请求访问窗口的时间相关 当远程端口大小为0时IUINT32 ts_probe, probe_wait;IUINT32 dead_link, incr;//发送队列struct IQUEUEHEAD snd_queue;//接收队列struct IQUEUEHEAD rcv_queue;//待发送队列struct IQUEUEHEAD snd_buf;//待接收队列struct IQUEUEHEAD rcv_buf;//用来缓存自己接收到了多少个ackIUINT32 *acklist;IUINT32 ackcount;IUINT32 ackblock;//用户信息void *user;//好像就用来操作数据的中转站char *buffer;//快速重传的阈值int fastresend;//快速重传的上限int fastlimit;//是否无视重传等其它设置窗口//steam模式的话,会将几个小包合并成大包int nocwnd, stream;int logmask;int (*output)(const char *buf, int len, struct IKCPCB *kcp, void *user);void (*writelog)(const char *log, struct IKCPCB *kcp, void *user);};
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 中国茶叶十大排名看看有没有你认识的
- 如何让你的大iPhone更舒适地单手使用
- “三”大方向,构筑5G下一站:中国移动张晓然详解R18标准演进
- 硅胶模具可以用热水烫吗 雪糕模具硅胶的使用前要用热水烫吗
- 好的茶叶多少钱斤 价格影响因素
- 笑傲江湖中小尼姑叫什么名字 笑傲江湖的小尼姑叫什么
- 感应水龙头原理 感应水龙头使用注意事项
- 杭州拟为保护西湖龙井茶立法,违规使用专用标识最高罚五万
- 杭州集中打击假冒“西湖龙井”:案值逾七千万,抓83人
- 茶叶蛋的做法放的什么茶叶
