SPECIFICATION
第 8 章 可靠性保障
8.1 可靠性模型
DTP 实现 必须 提供以下可靠性保障:
- 续传:在底层连接中断后恢复传输,不得 重传已成功接收的数据。
- 确认:接收方 必须 向发送方确认已成功接收的 Fragment。
- 重传:发送方 必须 在超时未收到确认时重传未确认 Fragment。
- 会话持久化:底层连接中断时 必须 持久化会话状态。
8.2 续传机制
8.2.1 续传协议
续传 必须 基于序列号实现,遵循以下流程:
发送方 接收方
| |
|-- Fragment (seq=1) -------------->| ✓ 接收
|-- Fragment (seq=2) -------------->| ✓ 接收
|-- Fragment (seq=3) -------------->| ✓ 接收
|-- Fragment (seq=4) ------- ✗ ----| 连接断开
| |
| [连接恢复] |
| |
|<-- ResumeReport (highest=3) ------|
| |
|-- Fragment (seq=4) -------------->| 从断点继续
|-- Fragment (seq=5) -------------->|
8.2.2 ResumeReport
接收方在连接恢复后 必须 发送 ResumeReport,定义如下:
interface ResumeReport {
collectionHighest: SequenceNumber;
injectionHighest: SequenceNumber;
}
| 字段 | 规范性要求 |
|---|---|
collectionHighest | 必须 为接收方在数据归集方向上已成功接收的最高序列号 |
injectionHighest | 必须 为接收方在数据注入方向上已成功接收的最高序列号 |
如某方向尚未接收任何 Fragment,对应字段 必须 为 -1 或实现定义的"未接收"标识值。
8.2.3 续传一致性
发送方收到 ResumeReport 后 必须 严格遵循:
- 从下一个序列号继续:从
highest + 1开始重新发送。 - 不重复发送:不得 重新发送序列号
<= highest的 Fragment。 - 不跳过:不得 跳过未确认的 Fragment(即未在缓存中确认接收的)。
8.3 确认机制
8.3.1 确认方式
实现 必须 提供 Fragment 接收确认。确认 可 通过以下方式之一实现:
- 显式 ACK 控制帧:接收方发送 ControlFrame,
controlType = "ack",details 包含已确认的最高序列号。 - 累积 ACK:在每个数据帧的扩展字段中携带反向方向的最高已接收序列号(推荐)。
- 批量 ACK:每接收 N 个 Fragment 发送一次 ACK(实现定义 N,推荐 为 16)。
具体确认方式 可 由实现选择,但接收方与发送方 必须 就所选方式达成一致。
8.3.2 确认时序
接收方 必须 满足:
- 在 Fragment 通过解密、Agreement 验证、DAG 验证后才能确认。
- 不得 在 DAG 处于
pending状态时确认(应在依赖解析后再确认)。 - ACK 中的最高序列号 必须 是已确认序列号集合的连续前缀的最大值。
8.4 重传机制
8.4.1 重传策略
发送方 必须 在以下条件下重传:
- 在协议配置的重传超时时间内未收到对应序列号的 ACK。
- 收到 ResumeReport 时,对未确认的 Fragment 重传。
8.4.2 重传配置
实现 应 提供以下可配置参数:
| 参数 | 默认值(推荐) | 说明 |
|---|---|---|
| 初始重传超时 | 5 秒 | 第一次重传等待时间 |
| 重传退避因子 | 2 | 每次重传后超时翻倍(指数退避) |
| 最大重传次数 | 5 | 超过后通知上层失败 |
| 最大重传超时 | 60 秒 | 重传超时上限 |
实现 必须 实现指数退避算法。
8.4.3 重传失败处理
当重传次数超过上限时:
- 发送方 必须 通知上层应用
RETRANSMISSION_TIMEOUT错误(6002)。 - 发送方 应 触发会话挂起或终止(实现定义)。
- 实现 不得 无限重传。
8.5 缓存管理
8.5.1 未确认 Fragment 缓存
发送方 必须 维护未确认 Fragment 缓存,满足:
- 每个已发送但未收到确认的 Fragment 必须 保留在缓存中。
- 收到确认后,必须 从缓存中移除已确认的 Fragment。
- 缓存 必须 有容量上限(实现定义,推荐 不少于 1024 个 Fragment 或 16 MB)。
8.5.2 缓存满处理
当缓存达到容量上限时,发送方 必须:
- 暂停发送新 Fragment。
- 通过
BUFFER_FULL错误(6001)通知上层应用。 - 在确认释放缓存空间后恢复发送。
- 不得 静默丢弃 Fragment。
8.6 会话管理
8.6.1 会话建立
CAP 完成身份验证与密钥交换后,DTP_Engine 必须 建立 DTP 会话:
- 必须 生成符合 RFC 4122 的唯一 Session_ID(UUID v4)。
- 必须 初始化 Session 数据结构(参见第 8.6.3 节)。
- 必须 将状态从
WaitingForCAP转换到SessionEstablished。
8.6.2 会话状态维护
DTP_Engine 必须 在会话期间维护双向的传输状态:
interface DirectionalTransferState {
currentSequenceNumber: SequenceNumber;
highestAcknowledgedSequenceNumber: SequenceNumber;
unacknowledgedFragmentCache: Map<SequenceNumber, Fragment>;
}
实现 必须 为每个传输方向维护独立的 DirectionalTransferState:
| 方向 | 字段名 |
|---|---|
| 数据归集(Terminal → Fay) | collectionState |
| 数据注入(Fay → Terminal) | injectionState |
8.6.3 Session 数据结构
完整的 Session 结构 必须 包含:
interface Session {
sessionId: SessionID;
masterIdentity: string;
slaveIdentity: string;
state: SessionState;
activeAgreements: Map<AgreementID, Agreement>;
collectionState: DirectionalTransferState;
injectionState: DirectionalTransferState;
createdAt: number;
lastActivityAt: number;
timeoutThreshold: number;
}
8.6.4 会话持久化
当底层传输连接断开时,DTP_Engine 必须:
- 立即将 SessionState 从
Transmitting转换到Suspended。 - 持久化以下内容到非易失性存储:
- 完整的 Session 对象(包括所有 active 约定)
- 双向 DirectionalTransferState
- 未确认 Fragment 缓存
- 持久化 必须 是原子的(要么全部成功,要么全部失败)。
8.6.5 会话恢复
底层连接重新建立后,DTP_Engine 必须 遵循以下恢复流程:
- 等待 CAP 重新验证。
- CAP 验证成功后,进入
Resuming状态。 - 从持久化存储中恢复 Session 状态。
- 接收方发送 ResumeReport(参见第 8.2.2 节)。
- 发送方根据 ResumeReport 从断点继续传输。
- 续传握手完成后转换到
Transmitting。
如恢复失败,DTP_Engine 必须:
- 转换到
Idle状态。 - 释放所有相关资源。
- 通过
SESSION_RESTORE_FAILED错误(5003)通知上层。
8.6.6 会话超时
实现 必须 实现会话超时机制:
- 必须 维护
lastActivityAt字段,记录最后一次活动时间。 - 当
now - lastActivityAt > timeoutThreshold时,必须 将会话设为超时。 - 超时的会话 必须 被关闭,相关资源 必须 被释放。
- 默认
timeoutThreshold推荐 为 30 分钟(1,800,000 ms)。
8.7 双向独立性
实现 必须 严格保证两个传输方向的独立性:
- 数据归集方向的状态变化 不得 影响数据注入方向。
- 一个方向的连接异常 不得 自动触发另一个方向的状态变更(除非底层连接整体断开)。
- 一个方向的序列号 不得 进入另一个方向的序列号空间。
- 一个方向的缓存 不得 占用另一个方向的缓存配额。
