IEC 104仿真工具实战指南:从联调排障到自研架构
2026/9/9 9:23:16 网站建设 项目流程

简介:面向电力系统自动化研发与测试人员的 IEC 104 规约客户端/服务端仿真工具,可用于模拟 SCADA 主站与 RTU 从站间的遥测、遥信、遥控、遥调通信,支持验证规约解析、命令下发及异常处理等场景。压缩包共 137 个文件,大小 14.55MB,以 C++ 源码(.cpp/.h)、Visual C++ 工程文件(.dsp/.dsw)、可执行程序(.exe)及动态库(.dll)为主,同时附带 .pdb、.obj 等编译调试产物,便于直接运行或二次开发。已有 706 人学习下载。资源内含 Master 与 Slave 两套 MFC 程序框架,对应客户端和服务端仿真;代码覆盖 ASDU/TCPU 分层处理、A 格式与 U 格式交互、断线重连与流量控制等关键逻辑,并配有工程说明文档,适合学习规约实现细节、开展接口联调与压力测试,是一份实用性很强的电力通信调试工具包。 前两天在配电站房现场调一台边缘网关的IEC104上报,从下午一直折腾到晚上九点,最后还是靠一台仿真工具定位到问题:网关在链路建立之后迟迟不发总召唤的激活终止帧,主站就始终认为数据没有传完。这种情形我遇到过太多次,所以出差电脑里必装一套IEC104 客户端、服务端仿真工具。这篇文章就围绕仿真工具这个主题,讲清楚它到底解决什么问题、配置时需要理解哪些协议骨架、客户端仿真和服务端仿真分别要具备什么能力、真实联调中怎么用它排雷,以及如果你想自己动手改一版,架构上应该怎么拆。

做电力自动化的人都知道,IEC 60870-5-104是目前远动通信里最常用的协议之一,主站、子站两个团队经常各管一段,真机子站又没法随便折腾,仿真工具就成了中间那个最可靠的"裁判"。不管你是做调度主站、配电终端、电力网关还是协议栈开发,这台工具用好了,能帮你把联调时间砍掉一大半。下面我按自己踩过坑的顺序来讲。

1. 为什么调IEC 104总得备一套趁手的仿真工具

1.1 现场联调的真实痛点

我做过的项目里,最常见的场景有两种:一种是主站平台先建好了,子站设备还在出厂测试,联调窗口就两三天;另一种是现场设备已经投运,你根本不敢随便改配置、重启、断链去验证异常逻辑。这两种场景下,拿着真机做测试都特别被动。

我记得有一次联调一台保护装置,对方厂家只给了一个IP和端口,连点表都是PDF扫描件。我想验证它在链路中断后会不会主动重连、重连后会不会重新做总召唤,但设备运行着,我不可能真去拔网线。哪怕能拔,旁边就是运行中的监控屏,出了问题没人担得起。这种时候,仿真工具的价值就出来了:我可以自己先模拟一个子站,把所有异常场景都过一遍,等行为符合预期了,再拿真机来验证。

另一个扎心的现实是,主站和子站往往不是一拨人开发的。两边都觉得自己实现得对,出了问题互相甩锅。仿真工具作为一个中立的参照物,能明确告诉你"报文就在这,谁没按规矩来自己看"。很多次联调会,解决问题的不是争吵,而是把抓包文件或仿真工具的日志往桌上一放,谁少回了确认帧一目了然。

1.2 仿真工具要解决的核心问题

说白了,IEC 104仿真工具要做的事情有两件:一是扮演一个"标准参考答案",让对方实现能对着它校验;二是扮演一个"故障注入器",把各种不正常的报文、不正常的时序发给对方,看对方会不会优雅地处理。

先说标准参考答案。你做子站,仿真工具扮演一个合规的主站,发起TCP连接后按顺序做STARTDT激活、总召唤、周期查询,你会看到它对于你上送的每一包数据都规规矩矩回S帧确认。如果工具日志里显示"收到未确认的I帧数量超过窗口限制",说明你的上送逻辑没有按停止等待确认的方式限制数据量,这就是潜在隐患。反过来你做主站,仿真工具扮演一个标准的子站,它会在收到总召唤后先回激活确认,再把所有点按顺序上送,最后回一个激活终止。如果你连这种最标准的子站都调不通,那问题基本就在主站自己身上。

再说故障注入。真实联调中很多问题不是"正常流程走不通",而是"异常情况没被正确处理"。比如仿真工具可以主动不发S帧确认,让对方陷入窗口满的停等状态;可以故意把一个I帧的序号重复发送;可以发一个未知的类型标识;可以在你召唤总召唤时只回一部分数据就不回了。这些场景用真机去模拟成本太高,但用仿真工具配置几秒就能跑一遍。联调前把这些负面用例过一遍,能少跑很多趟现场。

1.3 什么样的工具算"趁手"

市面上和IEC 104相关的工具其实不少,但真正趁手的不多。开源社区里常被拿来二次开发的包括C语言系的lib60870、Python接口的c104,以及Java系的OpenMUC j60870;商业电力测试仪厂商也大多内置了104模拟功能。我个人评价一个工具好不好用,就看四点:能不能同时切换客户端和服务端两种角色,能不能自定义点表和超时参数,能不能方便地注入异常,日志能不能导出成通用格式。

如果只是拿来临时看看报文,那其实任何带解析功能的工具都够用;但如果你跟我一样要把仿真工具嵌进联调流程甚至自动化测试里,那"角色可切换"和"异常可注入"这两点就是刚需。很多工具只能模拟一边,等你接到反向联调任务时又得换一个工具,来回学习成本很高。后文我会把这两种角色的能力边界拆开细讲。

2. 动手配置仿真工具前,先把60870-5-104的关键骨架摸清

2.1 APDU由APCI和ASDU组成,帧类型要看清楚

很多人在仿真工具里配参数时一头雾水,就是因为没理解报文的基本结构。IEC 104的报文单元叫APDU,前面6个字节是APCI控制头,后面跟的是ASDU数据区,ASDU不一定每帧都有。APCI的第一个字节固定是0x68,第二个字节表示后面剩余字节数,剩下的4个字节是控制域。控制域不同,帧类型就不同。

I帧是信息传输帧,只有它才能携带ASDU;S帧是监视帧,只用来做确认,表示"你发到编号多少的帧我都收到了";U帧是控制帧,不携带ASDU,用来做STARTDT激活/确认、STOPDT激活/确认、TESTFR测试帧的请求/确认。在仿真工具里看日志时,如果满屏都是S帧,说明对端TCP连接正常但应用层基本没数据流动;如果一直是U帧TESTFR,说明链路空闲,但双方还在通过测试帧保活。

实操中有个容易忽略的点:I帧里的发送序号和接收序号是15位逻辑序号,编码到字节里时整体左移了一位,最低位保持0。有些工具显示N(S)是0、1、2,有的工具直接按编码值显示0、2、4,两种显示方式都能在协议里找到依据,但如果你要手动构造报文或者核对抓包,必须搞清楚你手里这个工具用的是哪种显示习惯,不然排查序号问题时会绕很大一圈。

2.2 常用ASDU类型标识和点表映射

ASDU里最关键的是类型标识、可变结构限定词、传送原因、公共地址和信息对象地址。类型标识决定这一帧里装的是遥信、遥测还是遥控。常见的有:类型标识1是单点遥信,3是双点遥信,11是标度化值遥测,13是短浮点遥测,45是单点遥控,46是双点遥控,100是总召唤。记住这几个,就覆盖了日常联调八成以上的报文。

信息对象地址(IOA)是IEC 104里最让新人头疼的地方。它是信息对象的地址,通常用3个字节表示,不同厂商对IOA的定义方式五花八门,有的从1开始,有的从0开始,有的把点号分在地址的高位和低位。仿真工具里配置点表时,IOA范围必须和对方的工程点表严格对齐,否则就会出现"工具里能看到报文,但设备端就是不认这个点"的情况。我见过最极端的一个项目,两台设备用的都是标准104,但IOA编号规则一个按十进制连续编号、一个按功能码分段映射,两边联了整整两天才发现是地址含义理解不一致。

品质描述词也值得留意。一个遥信或者遥测点在数据后面通常还跟着一个品质字节,里面包含无效、非当前值、被取代、被闭锁这些标志位。品质字节在工具里往往是十六进制显示,比如0x80表示无效。如果你在仿真工具里看到对端上送的数据是"正常值+品质无效",那这个点就不应该在业务上参与判断。

2.3 启动流程与t0到t3这几个超时参数

IEC 104启动流程是有严格顺序的:TCP连接建立后,主站必须先发STARTDT激活,子站回STARTDT确认,链路才进入可传输数据的状态;之后主站再发总召唤,子站先回激活确认,再按点表把所有数据上送,最后回一个激活终止帧表示总召唤结束。很多"连上了但收不到数据"的问题,本质上就是在这个流程的某一环断了。

仿真工具里几乎都有超时参数配置,这几个参数看起来小,实际坑很大。t0是建立TCP连接的超时,默认30秒;t1是发送I帧之后等待确认的最长超时,默认15秒,超过就要重发;t2是接收方在空闲时主动发S帧确认的间隔,默认10秒;t3是链路空闲时发TESTFR测试帧的周期,默认20秒。k值代表最多允许未确认的I帧数量,默认12;w值代表收到多少个I帧后必须主动回S帧,默认8。

我建议平时把工具里的参数先按默认值用,出问题再改。有一次我把t2调成60秒,结果对端子站因为一直收不到S帧确认,以为链路有问题,k窗口很快就满了,数据上送直接停住。这个例子很典型:不是协议实现错,而是仿真工具的确认节奏和对端预期不匹配,导致对端进入了自我保护。所以调试时先恢复默认参数,排除这种"非业务性干扰"再往下查。

3. 客户端仿真和服务端仿真:两张完全不同的能力清单

3.1 客户端仿真:自己扮演调度主站

客户端仿真,就是工具扮演主站、调度端,你去连一台真实的子站设备,比如RTU、保护装置或通信网关。这种模式下,最基础的能力是主动发起TCP连接,正确完成STARTDT激活,然后发总召唤把设备里的所有数据拉一遍。

再往下,一个合格的主站仿真器要能发遥控命令,而且得区分"选择"和"执行"两步。遥控命令里带有一个S/E位,常见的流程是先发一个选择命令,等待子站回选择确认,再发执行命令,等待执行确认。有些子站允许只发执行不选择,有些严格要求先选择后执行。拿仿真工具做客户端时,你应该能自由配置这一步:只选择、只执行、还是先选择后执行。我在现场见过一个主站平台只发执行不发选择,把一台严格要求双确认的子站设备调得毫无反应,两边查了很久才发现是这个细节。

除了拉数据和下发遥控,客户端仿真还要能模拟主站的"懒"和"勤"。勤的模式好理解,就是启动链路后立刻总召唤,之后按周期重复总召唤;懒的模式则是建链之后不发任何应用数据,只靠S帧或者TESTFR保活。这两种模式用来验证子站的"主动性",尤其是子站能不能在收到总召唤后正确发出激活终止帧,这个行为很多协议栈实现得都不够标准。

3.2 服务端仿真:把一座厂站装进电脑

服务端仿真正好反过来,工具扮演子站,监听一个TCP端口,等着主站来连接。别以为"被动监听"就简单,真正折腾人的全是细节。

一个完整、规范的服务端仿真器至少要能在收到TCP连接后正确响应STARTDT激活;收到总召唤后先回激活确认,然后按配置的点表把所有点分批次上送,最后回激活终止。这里最难的是"分批":如果点表很大,几万个遥信遥测不可能一包塞完,你要按工具配置的每包最多信息对象数量拆帧,还得把发送序号、接收序号维护好,等待主站的S帧确认。如果主站一直不回S帧,你的发送窗口就会满,后续数据就发不出去。很多主站实现不好,恰恰在接收大量数据时S帧回得不及时,仿真工具会非常直接地把这个行为暴露出来。

除了被动响应,服务端仿真器还必须能主动上送。比如模拟一个遥信变位,主动发一包变化遥信,传送原因填突发;模拟遥测越死区,主动上一包新遥测值。这样主站那边就能验证它的报警、遥测刷新逻辑。再进阶一点,工具还应该能模拟子站重启:发一个传送原因是初始化的报文,然后等主站重新发起总召唤。如果主站收到初始化后还傻等旧数据,那就说明主站的重启处理逻辑有问题。

3.3 角色切换时别忽略的配置项

很多工具支持一键切换客户端/服务端角色,但切换后有几项配置特别容易漏。端口号是第一个坑:做客户端时你填的是对端子站的端口,默认2404;切到服务端时,你必须确认工具自己是不是在2404端口上监听,如果本机端口被占用,工具往往会在日志角落报一句bind失败,不仔细看就漏过去了。

公共地址是第二个坑。子站设备的公共地址(CASDU)一定要在仿真工具里配对,不然主站发来的报文公共地址对不上,仿真器很可能直接丢弃。我见过有人用服务端仿真接主站,怎么调都不通,最后发现公共地址填了0,而主站发的每个ASDU公共地址都是1。这种问题抓包很容易看出来,但界面配置时太容易忽略。

4. 联调中最容易踩的五个坑,以及完整排查链路

4.1 TCP连上了但一包数据都收不到

这个坑出现的概率极高。完整排查链路是:先看TCP连接状态是否ESTABLISHED;然后看有没有完成STARTDT激活握手;再看如果角色是主站,有没有发出总召唤;如果角色是子站,有没有配置自动上送。

我遇到过最典型的场景是,仿真工具客户端显示TCP已连接,但报文列表里面什么都没有,等多久都没反应。用Wireshark抓包一看,原来设备那边只接受了TCP连接,但一直没回STARTDT确认。设备端的协议栈处于未激活的初始状态,主站发什么应用数据它都不处理。这种时候再往业务层找就是浪费时间,问题就在握手这一步。

反过来,如果STARTDT都完成了,总召唤也发了,还是没数据,就要怀疑是不是点表为空或者周期上送没开启。仿真工具里一般都有一项"周期上送"或者"变化上送"的开关,很多人打开工具只配置了IP和端口,忘记勾选自动上送,于是设备端一帧数据都不主动发。这属于工具使用细节,但越是低级错误越会浪费整个上午。

4.2 对时看着成功,设备时间就是差几秒

对时命令在主站发来的是一个7字节的CP56Time2a时标,里面包含毫秒、分、时、日、月、年、星期,看上去很简单,但在工具里最容易出错的是时标字段的字节顺序。IEC 104时标通常是小端方式存储,毫秒字段在前两个字节,然后是分、时、日、月、年、星期。如果你在工具里看到对时时标解析出来是"2025-06-15 08:30:00.123",那一般是解析对了;要是工具直接把原始字节按大端显示成"2025-06-15 00:30:08.123"这种奇怪组合,就要怀疑解析层的问题。

还有一个实际经验:有些设备对时精度要求不高,只精确到秒;有些设备则要求毫秒精度。联调时如果发现设备时间和主站总有几十毫秒到几百毫秒的误差,先不要急着怀疑协议,用仿真工具客户端连续发三次对时,然后读设备时间看差值是否稳定。如果稳定差固定值,往往是时区或基准时间处理问题;如果差值在跳动,那就要看设备端的时钟守时精度,这不是104消息能解决的。

4.3 遥控发下去,设备纹丝不动

遥控问题排查起来最让人上火,因为明明报文也发了,设备也没报错,但开关就是不动。我的排查顺序是:先核点表,再核命令类型,再核S/E位,最后核品质标志。

点表不对最常见的表现是,IOA在工具里是十进制显示,设备点表是十六进制,两边没换算就填进去了。其次是单点遥控和双点遥控用错:单点遥控对应类型标识45,双点遥控对应46。一个双点遥信对象你拿单点遥控去操作,设备不响应完全正常。

S/E位更是隐蔽。有些设备界面不显示具体S/E值,但仿真工具里一般有明确的下拉选项。如果设备要求选择加执行两拍,而你只发了执行,你会发现设备回了确认帧但状态里带一个"命令不被接受"的提示。品质标志里的BL闭锁也是一个关键点,设备如果上送品质显示闭锁,遥控会被拒绝,这不是协议问题,是设备侧联锁逻辑在起作用。

4.4 遥测值在工具里明显不对

遥测解析不对,往往是类型标识用错。同一个遥测对象,不同厂商可能用标度化值(类型11)或者短浮点(类型13)。仿真工具如果按标度化值解析一个短浮点报文,显示出来的数字完全没意义。我建议在工具里对每个点显示"原始字节+解析值"两列,先看原始字节是否符合类型定义,再谈换算。

另一个常见问题是工程换算系数。IEC 104里的标度化值是一个带符号整数,要变成真正的电流、电压,通常还要乘以系数、加上偏移。有些设备把系数写死在文档里,有些设备直接把缩放后的整数当原始值发出来。仿真工具能不能给每个点配置系数,直接决定了你看到的遥测值可不可信。所以别急着说"设备上送值错了",先用工具关掉系数看原始值,再和点表里的量纲核对一遍。

还有一个容易误判的是"死区"。主站侧觉得遥测值该变没变,其实不是没变,而是变化量没超过设备设置的死区阈值,设备按规约不上送。仿真工具客户端模式下,可以用总召唤强制拉一次全量数据,如果全量数据是新的,说明设备本身数据没问题,只是变化上送被死区挡住了。

4.5 断线重连之后状态始终恢复不了

这个问题出现频率也很高,而且比首次连接更能暴露协议栈质量。正常的断线重连流程应该是:TCP重新连接完成后,重新做STARTDT激活,必要的话再重新总召唤。但很多实现里,TCP重连了,STARTDT也过了,主站就是不再发总召唤,或者子站自己重启之后没有主动通知主站。

排查链路一般是:看仿真工具日志里,断线后有没有收到对端的初始化报文(传送原因是初始化的报文);如果收到了,看主站有没有随之重新发起总召唤;如果没有发,那问题在主站的状态机,它没有把"对端重启"当作一个触发总召唤的事件。

另一个细节是序号。断线重连后,发送序号和接收序号往往需要复位。有些设备重连后继续用旧的序号,有些从0重新开始。仿真工具如果默认自动复位序号,而你的对端又要求连续序号,两边就会不断报序号异常。反过来也一样。我现在的习惯是,工具里同时打开序号显示,重连后第一眼就看N(S)、N(R)是否按预期变化,如果对不上,再决定要不要手动重置。

5. 想自研或扩展仿真工具,架构上我建议这么拆

5.1 协议栈、会话状态和界面必须分离

如果你不满足于用现成工具,想基于开源库或自己写一套仿真器,架构上第一个原则就是分层。至少要有协议编解码层、会话状态机、业务数据模型和界面展示四块。

协议编解码层负责把TCP字节流切分成一个个APDU并解析成结构体,也负责把结构体编码成APDU字节流。会话状态机维护连接状态、发送/接收序号、超时定时器、窗口大小。业务数据模型主要管理点表、当前值和品质位。界面展示只做一件事:把状态和数据渲染出来。这个分层的好处是,你可以在没有界面的时候直接用命令行或脚本调协议栈,方便自动化测试。

我见过很多自研工具把TCP逻辑和UI逻辑写在一个类里,后面想加脚本回放、想跑回归测试,几乎没法下手。分层虽然前期多花点时间,但后期改动成本会小很多。

5.2 数据模型要能直接映射工程点表

IEC 104工具的核心数据模型其实就是一张点表。每个点至少要包含以下字段:点位名称、IOA、类型标识、初始值、变化阈值、扫描周期、品质位、是否启用。用结构化的方式存这些点,不要写在散落的哈希表里。

工程实践里,点表经常是Excel或者CSV格式,仿真工具最好支持直接导入导出。导入时要把IOA换算、类型映射、系数设置都做掉。我记得有个团队自研了一个104服务端仿真,最耗时间的不是协议栈,而是把上万个点的点表手动录进配置界面。后来加了CSV导入,一次搞定。这块做得顺不顺,直接决定工具好不好推广。

5.3 脚本化跑场景,仿真器才有自动化价值

当成型工具能手动收发报文之后,下一步就是脚本化。最简单的脚本能力是:按照时间线自动执行动作,比如第0秒建链,第2秒发总召唤,第5秒模拟一个遥信变位,第8秒断线,第12秒重连。这种时间线脚本能覆盖掉日常联调里80%的回归场景。

再进一步就是断言。脚本里不仅要能执行动作,还要能检查对端行为是否符合预期,比如"总召唤发出后10秒内必须收到激活终止帧",超过了就上报失败。把这一层接进CI,每次主站或子站版本更新都自动跑一轮协议回归,能在早期发现很多低级回归。我现在参与的项目,已经把104仿真器作为测试桩接进持续集成里,效果非常明显。

脚本引擎选型上不用追求复杂,JSON序列描述加一个执行器就够了。真要支持Jython、Lua这类嵌入脚本也可以,但先别一步到位,最小实现能从文本文件读场景就足够解决大多数问题。

5.4 做一个最小可用工具的大致路线

如果你是从零开始自研,我的建议是分三个阶段。第一阶段只做TCP收发和APDU编解码,能连上对端,能用Wireshark验证你编出来的帧是正确的,这就完成了最难的部分。第二阶段加会话状态机,支持STARTDT、总召唤、S帧确认、t1/t2/t3超时,这时候你已经能跑通基本的数据上送和接收。第三阶段再加点表、遥控、对时、异常注入、脚本化。

不要一上来就想支持全部ASDU类型。IEC 104里类型有上百种,实际工程常用的就那十几个。先把遥信、遥测、遥控、总召唤、对时做扎实,覆盖掉95%的联调问题,剩下的等遇到具体需求再补。很多半途而废的自研项目,都是死在前期追求大而全上。

6. 把仿真工具用出生产力的几个习惯

6.1 学会主动制造故障

我见过很多人用仿真工具只做一件事:连上,收报文,看报文,关掉。这样用其实浪费了工具一半的价值。趁手工具的真正威力在于你能主动制造故障,把对端的行为逼出来。

比如你想验证主站在子站不发总召唤激活终止帧时会不会卡死,那就用服务端仿真,收到总召唤后回一包激活确认、上送几个点,然后什么都不回了,等主站自己超时。这种测试对协议栈的健壮性非常关键。再比如你想验证子站对重复序号的容忍度,拿客户端仿真故意把一个I帧连发两次,正常实现应该通过S帧确认给一个接收序号,逼着发送方发现序号异常。故障注入做多了,你对自己产品的边界心里会特别有数。

6.2 建立自己的场景配置库

工具是给人用的,但真正值钱的是你在里面沉淀下来的场景配置。每完成一个项目联调,我都习惯把仿真工程文件、点表、参数配置、异常测试脚本一起存档,命名规则是"项目名_设备型号_协议版本_日期"。

这个库越攒越值钱。后面再遇到类似设备或者类似主站,直接把上次的场景配置调出来改一改就能用,不用从零开始填参数。尤其是点表,每个项目都重新录一遍既浪费时间又容易出错。配置库里还要写上备注,比如"这个设备的遥控必须先选择后执行,否则会回拒绝"、"这个主站不会在断线后自动重发总召唤",这些经验是工具本身不会告诉你的。

6.3 别只信工具解析,交叉验证一次再下结论

最后一条建议,来自好几次被工具误导的教训。仿真工具的报文解析偶尔也会和你预期不一致,特别是涉及私有扩展、特殊类型标识、位级品质字段时,工具的解析未必准确。遇到可疑报文,不要急着按工具的显示下结论,用Wireshark打开同一段抓包,对照一下APDU长度、控制域字节、ASDU字段,两边都一致再定性。

Wireshark自带的IEC 60870-5-104解析器做得比较细,很多工具不认识的扩展类型它也能拆出原始字节。我现在的习惯是,仿真工具负责把流程跑起来,Wireshark负责在关键节点抓包留证。特别是客户现场扯皮的时候,一份干净的抓包文件比口头解释有用得多。工具是效率工具,但最终判断还是要靠自己对协议的理解,这个习惯陪着我避开了不少坑。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询