# 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: 远端主机自己计算出的延迟
