# mKCP 协议 mKCP 是流式传输协议,由 [KCP 协议](https://github.com/skywind3000/kcp) 修改而来,可以按顺序传输任意的数据流。 ## 版本 mKCP 没有版本号,不保证版本之间兼容性。 ## 依赖 ### 底层协议 mKCP 是一个基于 UDP 的协议,所有通讯使用 UDP 传输。 ### 函数 - fnv: [FNV-1a](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function) 哈希函数 - 输入参数为任意长度的字符串; - 输入出一个 32 位无符号整数; ## 通讯过程 1. mKCP 将数据流拆成若干个数据包进行发送。一个数据流有一个唯一标识,用以区分不同的数据流。数据流中的每一个数据包都携带了同样的标识。 1. mKCP 没有握手过程,当收到一个数据包时,根据其携带的数据流的标识来判断是否为新的通话,或是正在进行中的通话。 1. 每一个数据包中包含若干个片段(Segment),片段分为三类:数据(Data)、确认(ACK)、心跳(Ping)。每个片段需要单独处理。 ## 数据格式 ### 数据包 | 4 字节 | 2 字节 | L 字节 | | ---------- | ---------- | -------- | | 认证信息 A | 数据长度 L | 片段部分 | 其中: - 认证信息 A = fnv(片段部分),big endian; - 片段部分可能包含多个片段; ### 数据片段 | 2 字节 | 1 字节 | 1 字节 | 4 字节 | 4 字节 | 4 字节 | 2 字节 | Len 字节 | | --------- | -------- | -------- | --------- | --------- | ---------------- | -------- | -------- | | 标识 Conv | 指令 Cmd | 选项 Opt | 时间戳 Ts | 序列号 Sn | 未确认序列号 Una | 长度 Len | 数据 | 其中: - 标识 Conv: mKCP 数据流的标识 - 指令 Cmd: 常量 0x01 - 选项 Opt: 可选的值有: - 0x00: 空选项 - 0x01: 对方已发出所有数据 - 时间戳 Ts: 当前片段从远端发送出来时的时间,big endian - 序列号 Sn: 该数据片段时数据流中的位置,起始片段的序列号为 0,之后每个新片段按顺序加 1 - 未确认序列号 Una: 远端主机正在发送的,且尚未收到确认的最小的 Sn ### 确认片段 | 2 字节 | 1 字节 | 1 字节 | 4 字节 | 4 字节 | 4 字节 | 2 字节 | Len \* 4 字节 | | --------- | -------- | -------- | -------- | ----------------- | --------- | -------- | -------------- | | 标识 Conv | 指令 Cmd | 选项 Opt | 窗口 Wnd | 下一接收序列号 Sn | 时间戳 Ts | 长度 Len | 已收到的序列号 | 其中: - 标识 Conv: mKCP 数据流的标识 - 指令 Cmd: 常量 0x00 - 选项 Opt: 同上 - 窗口 Wnd: 远端主机可以接收的最大序列号 - 下一接收序列号 Sn: 远端主机未收到的数据片段中的最小序列号 - 时间戳 Ts: 远端主机最新收到的数据片段的时间戳,可用于计算延迟 - 已收到的序列号: 每个 4 字节,表示此序列号的数据已经确认收到 注释: - 远程主机期待收到序列号 [Sn, Wnd) 范围内的数据 ### 心跳片段 | 2 字节 | 1 字节 | 1 字节 | 4 字节 | 4 字节 | 4 字节 | | --------- | -------- | -------- | ---------------- | ----------------- | -------- | | 标识 Conv | 指令 Cmd | 选项 Opt | 未确认序列号 Una | 下一接收序列号 Sn | 延迟 Rto | 其中: - 标识 Conv: mKCP 数据流的标识 - 指令 Cmd: 可选的值有 - 0x02: 远端主机强行终止会话 - 0x03: 正常心跳 - 选项 Opt: 同上 - 未确认序列号 Una: 同数据片段的 Una - 下一接收序列号 Sn: 同确认片段的 Sn - 延迟 Rto: 远端主机自己计算出的延迟