
简介面向电力系统自动化与设备调试场景工具包提供了一个基于C#开发的IEC104协议客户端测试软件解决了同类工具操作繁琐、报文解析不直观的问题。软件支持客户端报文实时显示与逐字段解释可同步解析遥测、遥信、遥控、对时及SOE事件并能按需调整规约格式适用于协议联调、功能验证和学习研究。压缩包共包含13个文件总体积约2.17MB内有可执行主程序、运行所需的动态链接库、Excel格式的参数模板与数据文件、XML配置、文本说明等结构简洁便于直接运行和参数二次调整。工具还具备参数在线修改与系数设置、等量及增量赋值、语音报警、参数导入导出等实用功能明显提升了测试效率与便利性。截至目前已有6657人学习下载适合电力行业技术人员、协议开发者和测试工程师参考使用。需要留意的是软件未附带使用说明书需使用者具备一定的协议基础自行探索且仅限非商业用途。1. 为什么说iec104测试工具是电力自动化调试的便携弹药库iec104测试工具.zip这个看起来平平无奇的压缩包在电力远动和变电站自动化调试圈子里相当于一把随身的“协议万用表”。它通常以防安装形式分发解压即用不需要注册系统服务、不需要装数据库在Windows或Linux上直接模拟主站或从站把IEC 60870-5-104链路里的握手、总召、遥信遥测遥控一条条报文摆到桌面上。搞变电站自动化、配网终端验收、新能源场站远动调试的工程师现场最需要的就是这样一个便携工具。这篇笔记把整个工具链拆开讲协议该抓哪几块、参数怎么配、脚本怎么写、坑在哪。2. IEC 104协议测试前先背下三张表帧类型、ASDU类型和超时参数上手测IEC 104之前很多人容易犯一个方向性错误上来就抓包看到一串68 04 07 00 00 00就以为链路通了实际上后续的业务数据帧根本没跑对。IEC 104不像HTTP那样请求响应一一对应也不像Modbus那样问什么答什么它是一套带序号、带传输原因、带公共地址的异步规约。测试工具能不能派上用场取决于你对协议本身有没有建立一张清晰的地图。这一章把最核心的三块内容先立住帧类型、ASDU类型、超时参数。这三块是整个测试工具配置和报文解读的地基。2.1 帧类型与APCIU帧、S帧、I帧分别负责什么IEC 104的所有报文都遵循同一个APDU外壳启动符68 长度 控制域(4字节) 可选ASDU。控制域决定了这个帧是U帧、S帧还是I帧三种帧的职责完全不同测试工具配置错了帧类型对端会直接丢弃。用表说话帧类型控制域特征典型用途常见报文举例U帧控制域只有1个有效字节其余为0连接建立和断开、启动/停止数据传输STARTDT激活68 04 07 00 00 00S帧控制域低字节0x01高字节带接收序号确认对方发送的I帧不带ASDU68 04 01 00 06 00I帧低字节最低位0双字节序号携带实际ASDU业务数据总召、遥信、遥测、遥控工程上最容易出问题的点是把U帧当成可以随便发的控制命令。实际上U帧只有三种TESTFR测试链路、STARTDT启动数据传输、STOPDT停止数据传输各自带激活和确认两种形态。你要让从站主动上送数据必须先发STARTDT激活从站回STARTDT确认之后才能发I帧承载业务数据。很多测试工具默认不做这一步结果就是工具显示“连接已建立”但底下没有任何数据流动这就是典型的链路握手没走完。2.2 ASDU类型分类遥信、遥测、遥控和总召的类型号别记混ASDU应用服务数据单元是IEC 104真正承载工业数据的部分APCI只是外壳。ASDU里的第一个字节是类型标识TypeID这个字节决定后面怎么解析数据体。测试工具如果解析对不上TypeID轻则显示乱码重则把遥信值解析成遥测值整个测试结论都是错的。常用类型号需要形成条件反射TypeID类型名称数据内容场景1M_SP_NA_1单点遥信开关位置、设备状态3M_DP_NA_1双点遥信断路器分合双位置信号9M_ME_NA_1归一化遥测值电压、电流标幺值11M_ME_NB_1标度化遥测值带量纲的测量值13M_ME_NC_1短浮点遥测值浮点方式上送的遥测45M_SP_TB_1带时标单点遥信SOE事件记录100C_IC_NA_1总召唤主站发起全数据扫描101C_CI_NA_1电度召唤冻结电能数据45C_SC_NA_1单点遥控合分闸单点控制调试中最常见的误解是把类型45当成两个东西——实际上45在报文方向不同时语义不同主站发下来是遥控从站上送是带时标的遥信工具在解析时必须根据传输方向区分。2.3 t0/t1/t2超时参数和k/w窗口的工程意义IEC 104在全球变电站里跑了这么多年靠的是一套严格的超时和窗口机制。测试工具界面上的t0、t1、t2、k、w五个参数不是摆好看的它们决定链路在异常情况下多久能被发现、重发多少次算超时。常规取值如下参数含义典型值作用t0建立连接的超时时间30秒TCP连接后等待对端确认的时长t1发送后等待确认的超时15秒I帧或U帧发出后收不到确认就重发t2接收方确认的触发间隔10秒接收方最多等这么久必须回S帧确认k发送方最大未确认I帧数12个超过就停止发送w接收方最大未确认I帧数8个攒够这么多帧才回S帧确认实际测试中有一类翻车非常隐蔽主站和从站的t0取值不一致主站设30秒从站设10秒链路空闲时没问题一旦网络抖动超过10秒从站先断开主站还认为连接正常等下一个总召命令发过去才发现链路已经凉了。工具在测试前必须能把五个参数一并下发而且要和现场实际的调度主站参数对齐不要用默认值硬跑。3. 把iec104测试工具.zip解压跑通的最小配置五个参数一个都不能错拿到一个zip打包的IEC 104测试工具第一步不是连设备而是把工具本身跑干净。现场我见过太多人在这一步栽跟头双加没反应、连不上、启动报错、抓不到包最后发现全是环境或配置问题跟协议本身一点关系都没有。这一章按照实际操作的顺序来解压环境检查、通信参数配置、链路参数配置、回环自测。3.1 解压后先检查运行环境Java版本、VC运行库和端口占用zip形式的免安装工具依赖的是宿主系统里已有的运行库。最常见的坑有三个一是工具基于Java开发但现场机器只装了JRE 8工具需要JDK 17的特性直接报类版本错误二是Windows下缺少VC运行库exe双击后进程一闪而过连日志都不留三是端口被占用工具默认监听2404端口但机器上已经跑了一个旧版本的调试程序端口自然起不来。建议按这个顺序检查# 1. 看Java版本注意不是看装了没有而是看大版本号 java -version # 2. 检查2404端口是否被占用 netstat -ano | findstr 2404 # 3. 看进程启动后是否存活 tasklist | findstr iec104对应地Java版本不符就装对应的JRE并配好JAVA_HOMEVC运行库缺失就装对应架构的vc_redist端口被占用就找到占用进程PID确认不是系统进程后杀掉或者把测试工具的监听端口改到2405之类的空闲端口。有一点要提醒不要因为图省事把监听端口改掉然后直接连现场设备——现场调度主站就是固定连2404你改了自己监听方便但现场联调对方不改这才是真麻烦。3.2 五个核心通信参数本地IP、对端IP、端口、公共地址CA、站地址大多数IEC 104测试工具无论是图形界面还是配置文件核心参数只有五个。我们以常见的config配置文件为例一般长这样[network] local_ip192.168.1.100 remote_ip192.168.1.200 remote_port2404 [asdu] common_address1 station_address0逐一说明参数含义local_ip是工具本机绑定的网卡地址。现场笔记本电脑经常有线和无线同时在线如果绑错网卡报文从错误的物理口发出去抓包抓了半天发现根本不在链路上。remote_ip是对端设备地址注意这里不是广播地址也不是组播地址IEC 104就是纯TCP单播。remote_port默认2404除非对端特殊配置否则不要改。common_address是公共地址CA它对应的是RTU或变电站的地址不是设备内部某个点的地址。station_address在协议里不是一个独立字段很多工具用它来推导信息体地址的信息体地址区间配错会导致后面所有IOA偏移错位。这五个参数里CA最容易被当成“站号”填一个很大的数实际常用取值范围是1到65535很多现场的设备地址就是1、2、3这种小数字。填错了连接照样建立但总召上去后对端根本不认你这个公共地址数据一条都不会回。3.3 链路参数与总召节奏t0/t1/t2、k/w、总召间隔怎么设通信参数保证能连上链路参数保证连得稳。工具的链路参数设置界面一般长这样按上一章的参数表对齐到现场即可[link] t030 t115 t210 k12 w8 [cycle] interrogation_interval60interrogation_interval是总召间隔单位秒这个参数非常关键。IEC 104的从站不会主动把所有数据推给主站常规做法是主站周期性发总召命令从站把全部数据扫一遍上送两次总召之间的变化数据靠从站主动上报。测试工具扮演主站时总召间隔设太短比如1秒一次从站会被刷爆CPU占用拉满正常数据反而上送不及时设太长比如300秒一次现场变化信号不能及时看到测试效率极低。我的常用做法是链路连通性验证阶段用10到15秒间隔看链路稳定完整数据采集阶段再用60秒间隔跑一个完整周期。工具如果支持把总召条件和间隔分开配务必确认“启动后立即总召一次”这个选项勾上不要等第一个周期结束才发总召。3.4 先用回环地址自测不接现场设备也能验证协议栈跑通工具最稳妥的办法是先用127.0.0.1地址做回环自测。把工具配成主站模式监听本机2404端口再用另一个实例配成从站模式也监听本机2404端口两个实例通过回环地址互连。这样做的好处是隔离了网络物理通路、防火墙、对端设备配置等干扰变量只要自测能通工具本身的协议栈就是好的后面连设备出问题就能把排查范围缩小到对端和网络。自测通过的标准有三条主站能收到STARTDT确认不再反复重发启动帧总召发出后能收到类型100的激活确认之后再收到一批类型1、9、13的遥信遥测帧变化数据能实时上送在从站端手动翻转一个遥信点主站1秒内能看到对应报文如果上面三条都过工具侧就没有遗留问题接下来所有精力都可以放到现场链路和对端设备上。4. 自己写一个最小IEC 104主站脚本报文构造、总召下发与回包解析工具用顺手之后你会发现一个现实问题商用工具和开源工具的界面封装得太好你点个按钮它就发报文但报文长什么样、什么时候发、超时了怎么重发全是黑匣子。做协议测试的人手里必须有一套自己能完全控制的脚本这样遇到工具本身解析不了的特殊帧你才能手动构造、手动验证。这一章用Python写一个最小可用的IEC 104主站脚本覆盖连接、启动、总召、收包四步。4.1 建立TCP连接并发送STARTDT激活帧python # -*- coding: utf-8 -*- # demo_104_master.py # 最小IEC 104主站连接、STARTDT激活、总召、打印响应 import socket import struct import time def startdt_activate(): U帧 STARTDT激活控制域0x07 return bytes.fromhex(68 04 07 00 00 00) def build_total_call(common_addr: int): 构造总召C_IC_NA_1 I帧报文。 ASDU结构: 类型100 VSQ0x01 COT0x06(激活) CA(2字节) IOA(3字节) QOI0x14 asdu_type 0x64 # C_IC_NA_1 vsq 0x01 # 一个信息对象 cot 0x06 # 激活 # 用小端拼公共地址CA ca_low common_addr 0xFF ca_high (common_addr 8) 0xFF # IOA0x000000, QOI0x14 表示全局总召 asdu bytes([asdu_type, vsq, cot, 0x00, ca_low, ca_high, 0x00, 0x00, 0x00, 0x14]) # APCI: 68 0E 02 00 00 00, 长度0x0E4字节控制域10字节ASDU frame bytes.fromhex(68 0e 02 00 00 00) asdu return frame sock socket.create_connection((127.0.0.1, 2404), timeout5) # 第一步发送STARTDT激活 sock.sendall(startdt_activate()) # 第二步等待STARTDT确认(U帧确认, 控制域0x0B) resp sock.recv(1024) print(STARTDT响应:, resp.hex())这段代码的要点是U帧控制域的硬编码。68 04 07 00 00 00里的长度04表示后面只有4字节控制域控制域07高三位清零、低四位表示STARTDT激活对端必须回68 04 0B 00 00 00才表示确认。控制域写错一个字节对端不会回任何东西TCP连接是通的但协议层面不认你。4.2 构造总召报文并发送STARTDT激活确认之后紧跟着发总召。总召属于I帧承载ASDU数据报文构造的逻辑在上面代码的build_total_call函数里已经体现。重点讲几个关键字段0x64是类型100对应C_IC_NA_1。VSQ0x01表示这一个ASDU里只有一个信息对象。COT0x06是“激活”语义表示这是主站发起命令从站回的第一帧应该是COT0x07激活确认之后才是COT0x14对总召的响应这个顺序错了说明总召流程没走对。CA是公共地址要和对端配置一致。IOA0x00在这里不是随便写的全局总召的要求就是信息体地址从0开始从站才会全量扫描写错了从站只会扫个别区间。QOI0x14是召唤限定词表示“全局总召”只有这个值才会触发全数据扫描其他值比如0x15是子站总召行为完全不同。发送完总召后最好把读socket超时设置成3到5秒避免对端没响应时脚本卡死# 第三步发送总召并收取响应 sock.settimeout(5) sock.sendall(build_total_call(common_addr1)) data sock.recv(4096) print(总召响应帧:, data.hex())这段代码里的timeout5不是乱拍的。IEC 104的t1参数默认15秒发送后等确认的窗口就是15秒测试场景下把等待窗口压到5秒是为了快速暴露问题如果5秒内对端还没有任何响应基本可以判断要么CA配错、要么QOI不对、要么从站没进入运行状态没必要傻等15秒。4.3 解析回包ASDU类型、COT和遥信数据体收到回包后需要按APCI和ASDU两层拆开看。第一层确认长度字段是否与实际一致避免粘包或半包第二层逐字节解析ASDU。def parse_frame(data: bytes): 解析一个APDU帧的关键字段仅用于调试 if len(data) 6: print(帧长不足当前长度:, len(data)) return length data[1] if length ! len(data) - 2: print(f警告长度字段{length}与实际长度{len(data)-2}不一致) return # 控制域4字节, 后面就是ASDU asdu data[6:] if not asdu: print(纯控制帧无业务数据) return type_id asdu[0] cot asdu[2] # 传输原因低字节 ca struct.unpack(H, asdu[4:6])[0] print(f类型{type_id}(0x{type_id:02x}) 传输原因{cot} 公共地址{ca}) # 读取过程中注意处理多帧情况简单场景直接recv一次 try: frame sock.recv(4096) parse_frame(frame) finally: sock.close()解析这一步最容易忽略的是多帧问题。从站响应总召时数据量大一帧装不下会分成多帧连续发送每帧都是独立的APDU但TCP读取时可能一次recv就收到好几帧也可能一帧分两次才收完。测试脚本里不能假设一次recv对应一帧正确做法是循环读取用长度字段data[1]判断每帧的边界帧什么时候收完、下一帧从哪里开始都靠这个长度字段驱动。这也是为什么工具里看到的“报文条数”和wireshark里看到的TCP段条数总对不上——工具按APDU帧计数wireshark按TCP包计数一包可以含多帧一帧也可以跨多个TCP包。5. IEC 104测试工具踩坑记录现象、原因和解法协议测试工具跑不通绝大多数时候不是工具坏了而是规约细节没对上。这一章列五个我在实际项目中反复见到的坑每条都是真实踩过的。5.1 总召激活后从站毫无响应现象主站工具显示TCP连接正常STARTDT确认也收到了但总召命令发出去后从站既不回激活确认也不上送任何数据界面上一片空白。原因最常见的是QOI召唤限定词和IOA的组合不对。很多国产从站实现里全局总召的IOA必须从0开始QOI必须是0x14把IOA写成1从站就认为你在召唤一个不存在的信息对象直接丢弃。另外CA公共地址不对也会出现完全相同的现象。解决先用抓包工具看主站发出去总召帧的原始十六进制确认CA、IOA0x00、QOI0x14三个关键字节都正确再把CA切成和从站侧完全一致的数值回环自测一次确认工具侧没问题最后才连真实从站测试。这样三步排查下来90%的总召无响应问题都能定位。5.2 遥信值解析出来全部反相现象从站返回的单点遥信帧报文格式完全正确TypeID是1字节长度也对但界面上显示的开关状态和现场实际正好相反该合的分位该分的合位。原因单点遥信M_SP_NA_1的SIQ字节最低位SPI表示开关位置0代表分、1代表合这个定义是规约标准上的。但有些IED厂家习惯自己定义0代表合、1代表分而且不写在规约文档里。测试工具按标准解析自然就和现场对不上。解决这种问题不能靠改代码解决要让现场厂家确认SIQ位的定义。工具如果有“遥信极性”或“SPI取反”配置直接勾上取反再验证如果工具没有这个配置就在解析脚本里对SIQ最低位做一次异或再和现场实际状态核对一次。注意不要把“反相”和“双点遥信按单点解析”两种错误混在一起双点遥信是TypeID 3两个位分别表示00中间态、01分、10合、11故障态误用TypeID 1解析TypeID 3的报文数据一定是乱的。5.3 链路刚建好就周期性掉线现象主站和从站能建立连接也能正常传一段时间数据但每隔几十秒到几分钟就掉线一次重连后又恢复正常周而复始。原因链路参数的t1和t2不匹配。如果主站t115秒从站t210秒正常情况下从站每收到8个I帧或每10秒必须回一个S帧确认但主站的接收确认间隔和从站发送确认间隔对不上导致一方觉得对方已经确认了另一方觉得还没确认窗口溢出后直接断开。解决把t0、t1、t2重新对齐最稳的配置是t030、t115、t210主站从站必须一致。另一个隐蔽原因是链路空闲时双方都不发心跳IEC 104没有专门的心跳帧链路空闲时依赖TESTFR测试帧来保活如果工具没有周期发送TESTFR的机制长链路就会因为网络中间设备的空闲超时被掐断。工具里找一下“链路保活周期”之类的配置通常30秒发一次TESTFR激活能覆盖绝大多数中间设备的空闲断开机制。5.4 CA和IOA混用导致报文全部串号现象数据能上送但遥信表、遥测表全部对不上A站的开关量显示到B站下面或者同一个地址出现两组不同含义的数据。原因CA公共地址和IOA信息体地址概念被搞混。CA是站级地址一对多通信时用于区分不同的从站IOA是站内数据点地址用于区分布点。有些工具把站地址和数据点地址合并成一个输入框用户误填成同一个值或者把CA填成0导致数据全归到一个虚拟站下。解决在工具配置里把CA和IOA分开填。首先要向现场要一张点表明确每个遥信遥测的IOA编号规则比如遥信从10001开始、遥测从20001开始然后核对工具的IOA偏移量设置很多工具有“IOA起始偏移”参数填错整体偏移一个常数所有点全部串位。逐个点核对点表再下装测试不要批量导入就直接跑。5.5 zip工具双击后毫无反应现象从压缩包里解压出来的工具双击exe后没有窗口进程一闪就消失或者提示缺少DLL或者等了半天连日志都没有。原因三个常见因素。一是运行库缺失上面3.1节已经提过二是压缩文件本身有问题比如zip带有伪加密标志——解压时提示要求密码但实际没有或者解压出来的文件大小跟压缩包内索引不一致这种包里的主程序损坏启动必然失败三是exe依赖的配置文件路径被写死成绝对路径解压目录换了就找不到配置。解决先换7-Zip重新完整解压一次解压时确认文件列表和大小完整不要用系统自带解压工具直接拖出来如果提示伪加密在7-Zip里取消“加密文件名”选项强制解压。解压后右键exe属性看“兼容性”勾选“以管理员身份运行”再试。还不行就把exe所在目录加进Windows Defender排除列表曾经遇到过杀毒软件把免安装工具的授权文件当木马隔离进程起了但功能残缺排查了很久才发现是隔离区里有三个关键文件。6. 把测试工具从手点变成自动化回归脚本、故障注入与指标统计工具用熟之后下一层需求是重复测试和回归验证。手动点界面测一遍链路至少要五分钟而且每次手点的报文时序不可能完全一致做不了横向对比。把测试过程脚本化是测试工具落地到项目验收环节的必经之路。6.1 用Python把总召测试变成可重复的回归用例在第四章最小主站脚本的基础上把测试过程封装成用例函数输入是CA、QOI、预期遥信点数量输出是通过还是不通过。回归跑一遍相当于把原来手点一小时的工作量压缩到半分钟。一个稳定可用的回归用例至少要覆盖四件事STARTDT激活和确认、总召下发和激活确认、遥信点数量核对、遥测值范围检查。只测“能连上”没有任何意义链路通了不代表数据是对的。6.2 故障注入丢帧、乱序、延迟重发测试工具只测“正常情况”是不够的现场链路经常会抖动主站和从站对异常报文的处理能力才是验收重点。故障注入的常见手段有三种在发送端主动丢弃某个I帧观察从站能不能在超时后重发把两个I帧的发送顺序颠倒观察接收方的序号校验是否生效在I帧发出后手动延迟3秒再发后续帧观察窗口机制是否触发停止发送。这三种故障注入在真实设备上做起来都繁琐但在脚本里只是加个sleep或跳过一帧不发的区别。6.3 用一张指标表衡量链路质量自动化脚本跑完之后不要只看“通过”“不通过”把关键指标打出来。我的习惯是每次回归都记录四个数字总召响应时间从发出总召到收到第一帧响应数据的毫秒数、总召完成时间到收到最后一帧数据的毫秒数、链路中断次数和报文误码率。这四个数字横向对比同一台设备不同版本的程序比任何界面截图都有说服力。测试工具的终点不是“测通”而是“能量化地证明这个从站实现是可靠的”。我自己的习惯是每次接手一个新的远动项目先花半小时把这套脚本跑一遍把基线指标存档等到现场出问题再对指标能省掉一半的排查时间。这个习惯保留了好几年希望帮到你。本文还有配套的精品资源点击获取