第六章 数据传输

6.1 双向数据流

DTP 支持两个方向的数据传输,互不干扰:

方向名称说明
Terminal → Fay数据归集将终端产生的数据持久化存储到 Personal Data Heap
Fay → Terminal数据注入经过 iFay 过滤和判断后的最小化数据集

两个方向使用相同的 Logical_Frame 格式和处理流程,但维护独立的序列号空间和续传状态。

6.2 数据归集流程(Terminal → Fay)

完整的数据归集流程经过以下步骤:

终端应用
  │
  ▼ 提交数据
DTP_Slave Engine
  │ 1. 附加上下文元数据
  │ 2. 构建 LogicalFrame (Header + Payload)
  │ 3. 加密 Payload
  │ 4. 序列化 LogicalFrame
  │
  ▼ send(binary_data)
Transport_Adapter
  │
  ▼ onReceive(binary_data)
DTP_Master Engine
  │ 1. 反序列化 LogicalFrame
  │ 2. 验证 Agreement_ID
  │ 3. 解密 Payload
  │ 4. 验证 DAG 依赖
  │ 5. 更新序列号 + 发送确认
  │
  ▼ 存储
Personal Data Heap

6.3 数据注入流程(Fay → Terminal)

完整的数据注入流程经过以下步骤:

Personal Data Heap
  │
  ▼ 查询并过滤数据
DTP_Master Engine
  │ 1. 构建 Fragment + 上下文元数据
  │ 2. 构建 LogicalFrame
  │ 3. 加密 Payload
  │ 4. 序列化 LogicalFrame
  │
  ▼ send(binary_data)
Transport_Adapter
  │
  ▼ onReceive(binary_data)
DTP_Slave Engine
  │ 1. 反序列化 LogicalFrame
  │ 2. 验证 Agreement_ID
  │ 3. 解密 Payload
  │ 4. 更新序列号 + 发送确认
  │
  ▼ 交付数据
终端应用

6.4 Agreement_ID 压缩传输

为减少传输开销,DTP 支持 Agreement_ID 的压缩传输:

  • 当连续的 Fragment 属于同一约定时,仅在该批次的首个 Fragment 头部携带完整的 Agreement_ID
  • 后续 Fragment 的 agreementId 字段设为 null,表示沿用上一个

接收方处理规则:

  1. 收到携带 Agreement_ID 的 Fragment → 更新当前上下文的 Agreement_ID
  2. 收到未携带 Agreement_ID 的 Fragment → 关联到当前上下文中最近一次声明的 Agreement_ID
  3. 收到引用了未知 Agreement_ID 的 Fragment → 丢弃并发送错误通知

示例:

Fragment 1: agreementId = "abc-123"  ← 完整 ID
Fragment 2: agreementId = null       ← 沿用 "abc-123"
Fragment 3: agreementId = null       ← 沿用 "abc-123"
Fragment 4: agreementId = "def-456"  ← 新约定,完整 ID
Fragment 5: agreementId = null       ← 沿用 "def-456"

6.5 序列号管理

单调递增

每个 Fragment 携带传输序列号(Sequence_Number),在单次会话内单调递增。

双向独立

数据归集方向和数据注入方向维护完全独立的序列号空间:

数据归集方向 (collection):  seq 1, 2, 3, 4, 5 ...
数据注入方向 (injection):   seq 1, 2, 3, 4, 5 ...

一个方向的序列号变化不影响另一个方向。

6.6 原始时间戳保全

DTP 确保每个 Fragment 的原始时间戳(Origin_Timestamp)在整个传输过程中保持不变:

  • 记录数据在源端实际产生的时刻,而非传输时刻
  • 使用 UTC 时区和毫秒级精度
  • 经过序列化、加密、传输、解密、反序列化后,时间戳与发送前完全一致
  • 接收方保留原始的 Origin_Timestamp 不做修改

这确保了即使数据延迟上传(如离线场景),iFay 也能还原真实的时间线。

6.7 DAG 依赖验证

接收方在接收 Fragment 时进行 DAG 依赖验证:

  1. 环路检测:验证新 Fragment 的依赖关系不会在 DAG 中形成环路。若检测到环路,拒绝该 Fragment
  2. 依赖解析:若依赖目标 Fragment 尚未到达,将当前 Fragment 标记为"依赖待解析"状态并缓存
  3. 延迟解析:当被依赖的 Fragment 到达后,自动解析之前缓存的 Fragment