DIS 协议深度解析——从 SIMNET 坦克模拟器到 IEEE 1278 国际标准

📅 2026/8/18 11:19:24
DIS 协议深度解析——从 SIMNET 坦克模拟器到 IEEE 1278 国际标准
1983 年DARPA 启动了一个叫 SIMNETSIMulator NETworking的项目。目标很简单把分散在不同基地的坦克模拟器用网络连起来让四个车组能在同一个虚拟战场上协同作战。这个项目催生了后来统治军事仿真互操作领域三十年的标准——DISDistributed Interactive SimulationIEEE 1278。如果你做仿真、做半实物、做 LVCLive-Virtual-ConstructiveDIS 是你绕不过去的坎。AFSIM 里有完整的 DIS 实现src/core/wsf/source/dis/约 120 个源文件wizard 和 warlock 都内置了 DIS 监听器。这篇文章从协议本身、核心机制、开源生态到工程实践把 DIS 掰开讲透。一、从 SIMNET 到 DIS 7三十年的演进SIMNET 在 1980 年代的核心创新不是把模拟器连网——那时代已经有网络——而是死推算Dead Reckoning。每个模拟器只在实体状态发生显著变化时才发包其他时候让接收方用自己的运动模型外推。这条原则贯穿 DIS 至今是其唯一最重要的设计决策。1993 年SIMNET 协议正式成为 IEEE 1278-1993 标准。此后经历了七个大版本版本年份关键变化DIS 1 (Draft)1992初始草案DIS 2 (IEEE 1278-1993)1993第一个正式标准DIS 3-4 (Drafts)1993-1994扩展 PDU 种类DIS 5 (IEEE 1278.1-1995)1995全面修订增加 Logistics/Simulation ManagementDIS 6 (IEEE 1278.1a-1998)1998修正补丁DIS 7 (IEEE 1278.1-2012)2012重大升级72 种 PDU、13 族、增强可扩展性、更高保真度能力1996 年DoD 推出了 HLAHigh Level Architecture一度宣告 DIS 将被取代。1998-2001 年间NATO 甚至要求所有新建仿真必须用 HLA。但 DIS 没死——它太简单了部署成本几乎为零。2010 年 NATO 取消了 DIS→HLA 的强制迁移令。今天的现状是DIS 和 HLA 共存DIS 走轻量实时推演HLA 走复杂联邦建模。SISOSimulation Interoperability Standards Organization目前负责 DIS 标准的维护和枚举值更新每年发布一版SISO-REF-010DIS Enumerations定义了所有实体类型码、国家码、武器码等字段的合法取值。二、PDU 协议数据单元72 种消息13 个家族DIS 的核心是 PDUProtocol Data Unit——定义好的、固定格式的二进制消息。不像 JSON 或 XMLPDU 是定长二进制大端序编码字段偏移量在 IEEE 标准中写死。这是刻意设计——解包不需要任何解析器直接memcpy到结构体就行。2.1 通用头部每个 PDU 的前 12 字节是标准头偏移 长度 字段 0 1 协议版本 (DIS 6 5, DIS 7 7) 1 1 演练标识 (Exercise ID) 2 1 PDU 类型 (Type) 3 1 PDU 家族 (Family) 4 4 时间戳 (Timestamp) 8 2 长度 (Length) 10 2 填充/状态 (Padding/Status)总共 12 字节。值得注意的是PDU 类型和PDU 家族是分开的——类型是具体的消息比如 EntityState 1, Fire 2, Detonation 3家族是消息所属的大类Entity Information 1, Warfare 2, Logistics 3。2.2 13 个 PDU 家族DIS 7 定义的完整家族体系#家族典型 PDU场景1Entity Information/InteractionEntity State, Collision, Attribute实体存在与碰撞2WarfareFire, Detonation, Directed Energy Fire, Entity Damage Status开火、爆炸、毁伤3LogisticsService Request, Resupply Offer/Cancel/Received, Repair Complete/Response补给与维修4Simulation ManagementStart/Resume, Stop/Freeze, Acknowledge仿真管控5Distributed Emission RegenerationDesignator, Electromagnetic Emission, IFF, Underwater Acoustic, SEES电磁辐射6Radio CommunicationsTransmitter, Signal, Receiver电台通信7Entity ManagementAggregate State, Transfer Ownership, IsGroupOf/IsPartOf实体管理8MinefieldMinefield State/Query/Data雷场9Synthetic EnvironmentEnvironmental Process, Gridded Data, Point/Linear/Areal Object State环境数据10Simulation Management (Reliable)同上族的 TCP 版TCP 传输的管控命令11Live EntityTSPI, Appearance, Articulated Parts, LE Fire/Detonation实装接入12Non-Real-Time—非实时仿真13Information OperationsIO Action, IO Report信息作战但在工程实践中三个 PDU 占到了 90% 以上的网络流量Entity StatePDU Type 1、FirePDU Type 2、DetonationPDU Type 3。其他 69 种大多只在特定场景下出现。2.3 Entity State PDU最重要的一个包ESPDUEntity State PDU是 DIS 的绝对主角。它告诉全网我是谁、在哪、怎么动。完整结构字段 位宽 说明 PDU Header 96 标准头部 Entity ID 48 实体标识 (Site/Application/Entity 三元组) Force ID 8 敌我识别 Articulated Parameters(N) 128×N 铰接部件如坦克炮塔、飞机起落架 Entity Type 64 实体类型枚举(国家/领域/类别/子类别/型号) Alt Entity Type 64 对方视角的备选外观 Linear Velocity (X,Y,Z) 96 线速度 (m/s世界坐标) Entity Location (X,Y,Z) 192 位置 (m地心地固坐标 ECEF) Entity Orientation (ψ,θ,φ) 96 姿态 (弧度欧拉角Z-Y-X 顺序) Appearance 32 外观位掩码(燃烧/冒烟/隐身/灯火管制…) DR Algorithm 8 死推算算法编号 (1-9) DR Parameters 120 死推算参数块 Entity Marking 96 实体标记字符串(最多 11 字符) Capabilities 32 能力标志注意几个工程要点Entity ID是SiteID.ApplicationID.EntityID三元组全局唯一。SiteID 由 DIS 演练管理机构分配ApplicationID 是模拟器编号EntityID 是该模拟器内部的实体编号。三个都是 16 位无符号整数。坐标系统是地心地固坐标系ECEF原点在地球质心X 指向本初子午线与赤道交点Y 指向东经 90 度与赤道交点Z 指向北极。这是 64 位双精度(x, y, z)三元组——不是经纬高。姿态用 Psi偏航/Z 轴旋转、Theta俯仰/Y 轴旋转、Phi滚转/X 轴旋转三欧拉角表示单位是弧度。旋转顺序是 Z-Y-X先偏航再俯仰最后滚转。Appearance是 32 位位掩码每一位对应一个外观属性。比如 bit 3 是否冒烟bit 4 是否燃烧bit 5 是否闪烁灯光。不同的实体类型地面/空中/水面/水下/太空各有不同的位定义。2.4 Fire PDU武器开火时发送。关键字段字段 说明 Firing Entity ID 谁开的火 Target Entity ID 打谁 Munition ID 弹药实体 ID如果需要跟踪弹道 Event ID 事件编号Detonation PDU 引用此编号做匹配 Fire Mission Index 射击任务序号 Location in World 发射位置世界坐标 Burst Descriptor 爆炸描述符(弹药类型/战斗部/引信/数量/速率) Velocity 初速向量 Range 射程Fire PDU 和 Detonation PDU 通过 Event ID 配对——前者告诉你某弹药从某处发射后者告诉你某弹药在某处爆炸了。两者缺一不可只收 Fire 没有 Detonation接收方不知道打没打中只收 Detonation 没有 Fire接收方不知道谁打的。备注AFSIM 的WsfDisExchange类封装了 Fire-Detonation 配对逻辑。你需要手动在脚本中注册发射瞬间发出 Fire PDU和命中/脱靶瞬间发出 Detonation PDU——AFSIM 不会自动帮你做这个映射。实际上 DIS 规范里 Explosion PDU 的字段Fire Mission Index、Munition ID就是为这种配对设计的。三、死推算Dead ReckoningDIS 真正的核心技术死推算是 DIS 减少网络流量的关键手段。每个发送方在 ESPDU 中声明自己使用的 DR 算法接收方在没收到新 PDU 时用该算法推算实体的当前位置。3.1 DR 算法标记法DIS 用三元组DRM(F or R, P or V, W or B)标记算法第一个字母F 静止坐标系 FixedR 旋转坐标系 Rotating第二个字母P 恒定速率仅位置变化V 变速率位置速度变化第三个字母W 世界坐标系 WorldB 体坐标系 Body3.2 九种算法编号标记公式适用场景1Static不更新位置不变静止物体建筑物、固定雷达站2DRM(F,P,W)P P₀ V₀·Δt匀速直线运动巡航导弹、民航3DRM(F,P,W,B)P P₀ R·(V₀B·Δt ½A₀·Δt²)带加速度的直线运动4DRM(F,V,W)P P₀ V₀·Δt ½A₀·Δt²匀加速直线运动5DRM(F,V,W,B)P P₀ R·V₀·Δt ½(R·A₀)·Δt²体坐标系匀加速6DRM(R,P,W)P P₀ R(t)·V₀·Δt匀速 旋转坦克行进间射击7DRM(R,P,W,B)P P₀ R·(V₀B·Δt)体轴速度 带体轴加速度8DRM(R,V,W)P P₀ R(t)·[V₀·Δt ½A₀·Δt²]匀加速 旋转战斗机盘旋加速9DRM(R,V,W,B)P P₀ R(t)·[R·V₀·Δt ½(R·A₀)·Δt² 积分项]最复杂旋转体坐标系全场计算实践中80% 的实体用 DRM(F,P,W)DR 2就够了——匀速直线运动。飞机做高机动时偶尔用 DRM(R,V,W)DR 8。3.3 怎么决定何时发包发送方同时在跑两套位置自己的精准仿真模型算出的真实位置和对端会用 DR 算法推算出的预测位置。两套位置的欧几里得距离超过阈值比如 1 米就发一次新的 ESPDU 修正偏差。阈值是可调的精度优先调小带宽优先调大。这就是 DIS 的带宽-精度转换机制。不需要中心调度器每个发送方自行决策。四、传输层UDP 广播 可选 TCPDIS 默认用UDP 广播或多播。选 UDP 而不是 TCP 的原因广播天然一对多适合一个实体发、全演练场收的场景不需要三次握手和 ACK延迟低丢几帧位置更新没关系——DR 算法在接收方会继续推算TCP 只在 Simulation Management with Reliability 家族中使用Start/Stop/Acknowledge 等管控命令不能丢DIS 的标准多播地址是239.1.2.3演习用和224.0.0.x范围。每类 PDU 可以映射到不同的多播组——比如 Entity State 走组 AFire/Detonation 走组 B——这样接收方可以按需加入节省带宽。备注DIS 的 UDP 广播设计有一个致命缺点——没有 QoS 保障。在丢包率高的网络WiFi 或有线被占满关键的 Fire PDU 可能比 Entity State PDU 先丢。如果 Fire 丢了只收到 Detonation接收方只知道某处爆炸了但不知道谁打的。工程实践中建议把 Fire/Detonation PDU 映射到更高优先级的 TOS/DSCP 标记或者在 UDP 之上加一层简单的冗余重传。AFSIM 的WsfDisIO_Thread实现了 UDP 多播的发送和接收线程分离但没有内置应用层重传。五、AFSIM 中的 DIS 实现AFSIM 对 DIS 的支持不是能收能发的水平——它有一个完整的 120 文件的 DIS 子系统。5.1 架构应用层 ├── XIO 网络内部通信TCPUDP 双通道 │ └── WsfXIO_DisServiceXIO ↔ DIS 桥接器 │ ├── 订阅 XIO Track → 翻译成 ESPDU → 发出 │ └── 收到 ESPDU → 注入 XIO PlatformInfo → 广播 │ ├── DIS 协议层src/core/wsf/source/dis/ │ ├── WsfDisInterface 主接口初始化/连接/收发/过滤 │ ├── WsfDisPduFactory PDU 工厂二进制 ↔ PDU 对象转换 │ ├── WsfDisEntityState 实体状态编解码 │ ├── WsfDisFire / WsfDisDetonation 开火/爆炸编解码 │ ├── WsfDisEmission 电磁辐射 PDU │ ├── WsfDisTransmitter / WsfDisReceiver / WsfDisSignal 通信 PDU │ ├── WsfDisExchange 收发调度Fire-Detonation 配对 │ ├── WsfDisIO_Thread 独立 I/O 线程收发分离 │ └── WsfDisFilterAllowance 过滤规则按 Entity ID/Type 白名单 │ └── 传输层 └── WsfDisUDP_Device UDP 多播/广播设备 └── WsfDisFileDevice 文件设备记录/回放 DIS 演练 └── WsfDisPlaybackDevice 回放设备从文件读取 PDU 重放5.2 关键类说明WsfDisInterface入口类。管理 DIS 连接的生命周期——添加 UDP 多播设备、设置演练 ID、配置过滤规则、注册 PDU 回调。它自己不是单例一个 AFSIM 进程可以同时连接多个 DIS 演练。WsfDisPduFactory二进制 PDU 的无脑解析器。read()方法读一个字节流识别 PDU 类型创建对应的 C 对象WsfDisEntityState、WsfDisFire等。pack()方法反过来打包成发送缓冲区。WsfDisFilterAllowance不是所有 DIS 流量都要处理。这个类按 Entity ID站点/应用/实体、Entity Type国家/领域/类别、Force ID 做白名单/黑名单过滤。一个 AFSIM 想定可能只想看红方的空中实体过滤规则写在这里。WsfDisIO_Thread独立线程收发。DIS 是 UDP不需要阻塞但 AFSIM 的仿真主线程不能等网络 I/O——DiskIO_Thread 把收包和主仿真解耦。收到的 PDU 入队等AdvanceTime()调时批量处理。WsfDisExchange处理Fire→Detonation 匹配的类。维护一个飞行中的弹药映射表每收到一个 Detonation PDU 就查找对应的 Fire PDU补全谁→打谁→打中哪的战斗链。WsfDisFileDevice / WsfDisPlaybackDevice一个往磁盘写 PDU记录整个演练一个从磁盘读 PDU回放。DIS 没有中心服务器记录所有 PDU——每个接收端靠这个文件设备自己存档。5.3 AFSIM 里怎么配置 DISAFSIM 的dis_interface输入块配置示例简化dis_interface { exercise_id 1 site_id 42 udp_device { interface 192.168.1.100 port 3000 multicast_address 239.1.2.3 } entity_mapping { entity_type 1:1:225:1:1:1 # 空中/战斗机/F-16 afsim_type F16 } }注意entity_mapping——DIS 用数字编码实体类型SISO 枚举表AFSIM 用字符串名。这个映射表是必须写的否则 AFSIM 不知道1:1:225:1:1:1应该映射到哪个 AFSIM 平台类型。六、开源 DIS 生态你不需要从零实现 DIS。NASA、美国空军、加拿大国防部的工程师们已经维护了一套成熟的开源栈open-dis多语言https://github.com/open-dis语言仓库Stars成熟度Copen-dis/open-dis-cpp126生产级CMake 构建支持 DIS 6/7Javaopen-dis/open-dis-java55生产级Maven Central 发布Pythonopen-dis/open-dis-python78成熟含 AFSIM twin connector 示例C#open-dis/open-dis-csharp39成熟JavaScriptopen-dis/open-dis-javascript18可用于 Web 可视化open-dis-python 的 AFSIM Twin Connector直接提供一个 Python 示例向 AFSIM DIS 监听器发送移动实体# examples/afsim_twin_connector.pypython3 afsim_twin_connector.py--destinationafsim_ip--port3001\--rate-hz10--speed-mps15.0--turn-rate-dps5.0这个脚本每 100ms 发一个 ESPDU实体以 15m/s 速度飞行、每秒转向 5 度。AFSIM 收到后如果dis_interface配置了对应的entity_mapping就能在 wizard 里看到这个外部实体。DIS 教程必读https://github.com/open-dis/dis-tutorial——自称DIS: The Missing Handbook是 DIS 协议最完整的中文/英文教程合集覆盖从 PDU 类型到死推算实现的所有主题。七、DIS vs HLA vs XIO什么时候用什么维度DIS (IEEE 1278)HLA (IEEE 1516)XIO (AFSIM 原生)通信模型UDP 广播/多播RTI 发布-订阅TCPUDP 双通道 Service 模式发现机制无靠广播自然接收RTI 中心注册UDP 心跳自动发现消息格式定长二进制72 种 PDU用户自定义 FOM74 种多态 Packet 类型带宽效率低全演练广播高仅订阅数据中按连接和订阅路由部署复杂度极低一条命令高需要 RTI零配置自动发现时间管理无内置完整时间管理内置时间同步 控制可靠性无UDPRTI 可选可靠TCP 可靠 UDP 不可靠扩展性固定 72 种 PDUFOM 任意定义PacketRegistry 动态注入适用范围实体级交互位置/开火联邦级多仿真系统聚合AFSIM 内部生态结论AFSIM 实例之间用 XIO。自动发现、类型化 Packet、订阅管理、时间同步全内置。不要用 DIS。AFSIM → 外部仿真系统用 DIS。它是一个国际标准任何仿真引擎都支持。open-dis 生态覆盖 6 种语言。多系统联邦建模用 HLA。当你需要把 AFSIM、CMO、STK 和自研 C2 系统组成一个联邦时HLA 的 FOM 机制比 DIS 的固定 PDU 灵活得多。快速原型验证用 DIS。下载 open-dis-python写 30 行代码发 ESPDUAFSIM 里配dis_interface10 分钟跑通。八、工程实践十条经验Entity ID 是全局唯一的别乱设。SiteID 和 ApplicationID 在同一演练中不能冲突。多人协作时先约定好 ID 段。死推算阈值是调参关键不是越小越好。1 米阈值 10 架飞机 × 30Hz 网络可能撑不住。先用 5 米阈值跑看带宽再逐步降。Fire PDU 丢了影响远比 ESPDU 丢失大。ESPDU 丢了有 DR 补救Fire 丢了战斗链断裂。考虑把 Fire PDU 映射到更高网络优先级。Entity Type 枚举表是 600 页的 PDF。SISO-REF-010 定义了所有国家的所有军种的每种装备。但你日常只用到几十种——建好自己的映射表就行了别试图背下来。DIS PDU 是 Big-Endian。x86 是 Little-Endian。写代码时记得htonl()/ntohl()转换。open-dis 库已经帮你做了直接用就行。Wireshark 有 DIS 解码插件。打开 Wireshark → Analyze → Enabled Protocols → 搜 DIS → 启用。然后就能在抓包里看到Entity State: F-16 at (1234.5, 5678.9, 3456.7)而不是一堆 hex 数字。多播地址不要随便选。239.0.0.0/8 是管理员范围私有224.0.0.0/24 是本地链路不能跨路由器。跨子网用 239.1.x.x 并配置 IGMP。DIS PDU 是定长但可扩展。ESPDU 尾部可以追加 Articulated Parameters每 128 bits 一个铰接部件描述。最多 78 个——大概是一条长机翼带 10 个挂架的水平。演练 ID 是安全隔离边界。同一个多播组上跑来两个不同演练的 DIS PDU靠 Exercise ID 区分。AFSIM 的exercise_id配置就是这个用途。DIS 没有我上线了机制。UDP 广播是无连接的。接收方需要实现超时检测——如果一个 Entity ID 在 N 秒内没收到任何 PDU判定它离线。AFSIM 的WsfDisInterface有内置的实体超时清理。备注第十条是个常见的坑。很多人在 wizard 里看到 DIS 实体进来后一直停在原处不动以为 DIS 断了——其实是因为发送方停止发包但 DR 算法也在最后一次接收到的位置上停止了DR 1 是静态的。正确做法是AFSIM 应该以接收到的 ESPDU 中声明的 DR 算法类型持续外推直到超时。检查你的dis_interface配置里的entity_timeout参数。九、总结DIS 是一块 30 年的老砖头但它至今没有真正被替代。原因有三第一极简部署——一条 UDP 多播命令全网可见不需要服务端、不需要注册中心、不需要配置文件除了 entity_mapping。第二死推算让它在低带宽下也能工作——这个 1983 年的设计思想放到今天依然是最优的带宽换精度策略。第三开源生态成熟——open-dis 六种语言实现Wireshark 解码插件NPS 的教材和示例AFSIM 的完整 DIS 子系统。不需要从零开始。如果你在做 AFSIM 相关的分布式仿真理解 DIS 的理由很简单——它是那个和外部世界对话的通用语言。AFSIM 内部用 XIO对外用 DIS。前者是自己家的电话线后者是国际通用电报码。两条线都要通但别搞混了。