Skip to content

网闸连接器 UDP 传输协议规范

版本: 1.0

概述

网闸连接器在入口代理和出口代理组件之间,基于 UDP 使用一个自定义的、轻量级的应用层协议。该协议旨在通过将大型、不透明的二进制数据块分割成更小的 UDP 数据包,并在接收端重新组装它们,从而可靠地跨网闸传输这些数据。

该协议提供以下关键特性:

  • 消息分片与重组:允许传输大于标准 UDP 载荷大小的数据块。
  • 丢包检测:使用序列号系统来检测丢失的数据包。
  • 连接生命周期管理:包含用于启动、关闭和心跳维持的特殊消息类型。

包结构

在传输组件之间交换的每个 UDP 数据包都遵循一个固定的头部结构,其后跟一个可变长度的载荷。

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Message Type |               Sequence Number                 |
|               |                (LSB, 24 bits)                 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Sequence Number|         Payload Length        | Remaining Pkts|
| (MSB, 8 bits) |         (Little-Endian)       |     (LSB)     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Remaining Pkts|                                               |
|     (MSB)     |                   (Padding)                   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

头部字段

头部大小固定为 9 字节

  • 消息类型 (Message Type) (1 字节)

    • 一个 8 位无符号整数,定义了数据包的用途。详见消息类型
  • 序列号 (Sequence Number) (4 字节)

    • 一个 32 位无符号整数,采用小端序 (Little-Endian) 格式。
    • 每发送一个数据包,该数字加一。
    • 接收方用它来检测丢包。序列号 0 是一个特例,当乱序接收时(例如,在 StartUp 消息之后),不表示丢包。
  • 载荷长度 (Payload Length) (2 字节)

    • 一个 16 位无符号整数,采用小端序 (Little-Endian) 格式。
    • 指定当前数据包中 Payload 字段的大小(以字节为单位)。
    • 对于 DataDataFirst 数据包,该值通常是最大载荷大小 (MAX_PAYLOAD_SIZE_BYTES),但分片消息的最后一个数据包可能更小。
  • 剩余包数 (Remaining Packets) (2 字节)

    • 一个 16 位无符号整数,采用小端序 (Little-Endian) 格式。
    • 指示还需接收多少个数据包才能完成当前数据块的传输。
    • 对于 DataFirst 数据包,此值表示该数据块后续数据包的总数。
    • 对于 Data 数据包,此值随每个接收到的数据包而递减。
    • 当此值为 0 时,表示当前数据包是该数据块的最后一个包。

载荷 (Payload)

  • 载荷 (可变大小)
    • 原始数据块的原始二进制数据段。
    • 此字段的大小由头部中的 Payload Length 字段定义。

消息类型

Message Type 字段决定了接收方如何处理数据包。

名称描述
0DataFirst标记一个新数据块的第一个数据包。接收方从 WaitingForFirstData 状态转换到 WaitingForData 状态,并使用 Remaining Packets 字段来了解还需要期望多少个数据包。
1Data一个分片数据块的后续数据包。接收方收集这些数据包,直到 Remaining Packets 为零,然后重组完整的块。
2StartUp发送方初始化时发送的控制消息。接收到后,接收方将其期望的序列号重置为 0,并返回到 WaitingForFirstData 状态,丢弃任何部分接收的数据。
3HeartBeat一个心跳维持消息。接收方记录其接收情况并保持当前状态。它不影响数据处理。
4Shutdown一个控制消息,指示发送方正在关闭。接收到后,接收方将终止其处理循环。

状态机与重组逻辑

接收方使用一个状态机来处理数据包的重组。

  1. 初始状态: WaitingForFirstData

    • 接收方处于空闲状态,等待新的数据传输开始。
    • 它只接受 DataFirstStartUpHeartBeatShutdown 数据包。任何 Data 数据包都将被丢弃。
  2. 接收 DataFirst

    • 当一个 DataFirst 数据包到达时,接收方将其载荷存储为新消息的第一部分。
    • 如果 Remaining Packets0,则消息是完整的。载荷被写入输出缓冲区,状态保持为 WaitingForFirstData
    • 如果 Remaining Packets 大于 0,接收方转换到 WaitingForData(N) 状态,其中 N 是此消息的总包数 (Remaining Packets + 1)。
  3. 状态: WaitingForData(N)

    • 接收方正在为一个分片消息积极收集数据包。
    • 它期望 N-1 个后续的 Data 数据包。
    • 每个传入的 Data 数据包的载荷都根据其在序列中的位置(使用 Remaining Packets 值计算)存储在中间缓冲区中。
    • 如果在此状态下意外收到一个 DataFirst 数据包,当前的重组将被中止,部分数据被丢弃,并用这个新包开始一个新的重组过程。
  4. 接收最后一个 Data

    • 当一个 Remaining Packets 等于 0Data 数据包到达时,它标志着消息的结束。
    • 接收方将中间缓冲区中所有存储的载荷组合成一个单一、连续的字节数组。
    • 这个重组后的数据块随后被写入输出 bip_buffer,供下游组件使用。
    • 状态机转换回 WaitingForFirstData
  5. 丢包处理

    • 在每收到一个数据包时,接收方都会将其 Sequence Number 与其期望的序列号进行比较。
    • 如果 incoming > expected,接收方检测到一个或多个数据包已丢失。
    • 当检测到丢包时,接收方将中止当前消息的重组,丢弃该消息的所有已缓冲数据,并将其状态重置为 WaitingForFirstData。这确保了损坏或不完整的数据块不会被转发。