简介:《南瑞继保网络103规约》是一份面向电力系统自动化领域的协议说明文档,主要服务于远动设备(RTU)与调度中心之间的数据交换,围绕遥测、遥信、遥控、遥调等“四遥”功能展开讲解。文档基于IEC 60870-5-103标准,介绍南瑞继保在兼容性、安全性、通信效率、故障处理等方面所做的优化与扩展,并结合网络环境适应性给出了工程应用层面的解读。压缩包内共1个文件,为doc格式文档,大小3.38MB,内容较为集中,便于针对协议细节进行查阅和对照学习。目前已有1977人学习,说明其在电力系统调试与维护场景中具有一定参考价值。读者可从中了解网络103规约的总体结构、命令帧与应答帧的组成、错误处理机制以及典型应用注意事项,有助于进行设备接入、协议调试和系统集成。
1. 网络103规约不是串口103的网线化:先弄清它在现场解决什么
网络103规约,对做过变电站监控后台集成的工程师来说,是绕不开的一关。继电保护装置的动作事件、遥信变位、测量值、故障录波,最终都要靠它送到监控后台和远动主站;南瑞继保的PCS系列保护装置在新建站里基本都走网络103。可很多人上手就翻车:把串口103的调试思路直接套到网络103上,结果要么后台链路闪断,要么SOE时标对不上。它真正改变的是整个通信模型:TCP流里没有串口那样一问一答的链路层节奏,一个应用报文可能被拆成几个TCP段,也可能几帧粘在一起,解析时差一个字节就全废。这篇文章把网络103的报文结构、解析方法、配置步骤和现场坑位一次讲透,适合正在做保护装置接入、写驱动解析工具或者被后台黑匣子折磨的同行。
2. 网络103报文的骨架:APDU、控制域与ASDU如何协同工作
2.1 同一个0x68,在串口和网络里交付方式完全不同
串口103规约走的是FT1.2帧格式,典型结构是起始字符0x68、长度、控制域、ASDU,帧尾还有校验和与0x16结束符。链路层有严格的确认重发机制,主站和从站之间一问一答,一个帧没收到马上重发。网络103把同样的APDU放进了TCP流,传输可靠性交给TCP协议栈,TCP层负责重传和排序,应用层不再需要那一套链路层握手。这个变化听起来是简化,实际上带来两个新问题。
第一个问题是粘包和拆包。TCP是字节流,没有报文边界。发送方可能把两个APDU连续推过来,接收方一次read可能读到半个帧加一个完整帧加另一个帧的尾巴。第二个问题是帧边界的识别习惯被破坏。很多老工程师从串口转过来,下意识去找0x16结尾,结果网络流里根本没有这个字节。更坑的是,有些变电站的串口服务器设备会把串口FT1.2帧原封不动地封装成TCP发送,这时候你抓到的包里又有0x10开头、0x16结尾的串口帧痕迹,如果解析器还按网络103的纯APDU方式切分,就会把帧头和帧尾当成ASDU内容解析出乱码。
所以解析网络103的第一步不是看报文内容,而是先确认现场到底是纯网络103还是串口转网络的封装。判断方法很简单:抓包后看TCP payload开头,如果是连续的0x68开头帧,就是纯网络103;如果出现0x10 0x68或者0x68结尾跟着0x16,那就说明有串口帧的遗留,解析时要先把FT1.2的壳剥掉。南瑞继保新装置站控层口一般是纯网络103,但老站改造时通过串口服务器转出来的情况非常多,用网线直连调试时最干净。
2.2 APDU固定头与长度字段的边界
网络103的APDU结构沿用了IEC 60870-5-103的基本形态,一个完整的APDU由启动字符、长度、控制域和ASDU组成。启动字符固定是0x68,长度字段表示从控制域开始到APDU末尾的字节数,也就是说整帧实际长度是长度值加2。这个细节很重要,很多人解析时把长度理解成整个帧长度,导致缓冲切割差两个字节,后面的帧全部错位。
控制域在apdu[2]位置,一个字节,里面承载的是链路功能码、确认标志、访问要求等位信息。调试过程中最常看到的几个控制域值是0x09、0x49、0x0B、0x0F之类的组合。这一字节决定了当前帧是主站发来的请求、从站发来的确认,还是链路测试命令。虽然我们写解析脚本时一般不深究每一个bit,但它能很快区分一个帧到底是后台发出的总召唤还是装置返回的数据,这对抓包分析时的方向判断极有帮助。
这里给一个典型的APDU结构表格,方便对照抓包数据:
| 偏移 | 字段 | 字节数 | 说明 |
|---|---|---|---|
| 0 | 启动字符 | 1 | 固定0x68 |
| 1 | 长度L | 1 | 从控制域到帧尾的字节数 |
| 2 | 控制域C | 1 | 链路确认、功能码等标志 |
| 3 | ASDU | L-1 | 应用服务数据单元,承载具体信息 |
一条TCP报文里可能包含多个这样的APDU,解析时先用0x68定位起点,再用长度值切分,循环处理完整个缓冲区即可。
2.3 ASDU里三个必须认识的字段:类型标识、传送原因和公共地址
ASDU是实际信息的载体,它的结构在103规约里有明确的顺序约定。开头的类型标识和传送原因是最先要认识的。类型标识决定了这条报文是什么类型的数据,常见的有:类型标识1是带时标的事件信息,保护动作报文基本属于这一类;类型标识2是带时标的变位遥信;类型标识9是测量值;类型标识100是通用分类数据,总召唤、定值读写都用它承载。看到哪个类型标识,就能大致判断当前帧的用途。
传送原因紧跟类型标识之后,用于说明这条信息是“突发上送”“循环上送”还是“召唤响应”。公共地址一般紧随其后,在103规约里通常占用一个字节,对应装置地址或站地址。后台通道配置的公共地址必须和装置侧一致,否则装置会把后台的帧直接丢掉,这是现场最常见的“链路通但数据空”的原因之一。
ASDU里真正和信号对应的是功能类型FUN和信息序号INF。保护装置把内部每一个信号映射成一个FUN/INF组合,比如某个厂家的线路保护装置把“A相保护动作”放在FUN=0x50、INF=0x01,把“重合闸出口”放在FUN=0x50、INF=0x0A。不同工程、不同装置的映射完全不一样,必须从装置的组态点表里读取,不能照抄别人的配置。我们在后续对点章节会单独讲FUN/INF的点表核对方法。
2.4 总召唤、链路测试和变化上送:后台和装置的三方会话
网络103的通信模型里,后台是TCP客户端,保护装置是服务端。装置在指定端口上监听,后台主动发起TCP连接。连接建立之后,后台会先发链路请求,装置响应后,后台再发起总召唤,要求装置把当前所有遥信状态、测量值和保护事件全量上送一遍。装置收到总召唤后按顺序回送所有信息,回送完毕后再给一个总召唤结束标志。
正常运行阶段,装置通过变化上送方式主动把新的遥信变位和保护动作报文推给后台,不再等后台轮询。这种模式的好处是实时性好,SOE事件能毫秒级到达后台;坏处是一旦TCP连接断开又恢复了,装置缓存里没有新的变化事件,后台画面上所有数据都是空的。解决这个问题的正确做法是后台在链路重连后自动发起总召唤,或者周期性地每30秒到60秒发一次总召唤来兜底。很多后台组态工具默认没有打开这个自动总召功能,这就是大量现场装置重启后黑屏的根源。
链路测试报文也是必须保留的背景流量。后台通常每10秒左右发一次链路测试帧来维持TCP连接存活,装置收到后会回一个确认。抓包时如果看到这种周期性小帧,说明链路和后台保活机制是健康的;如果链路测试帧发出去没人理,那问题大概率在装置侧的规约模块没有正常运行。
3. 抓包解析网络103:用Python脚本把APDU拆开看
3.1 抓包准备:端口、接口和过滤条件
调试网络103第一件事就是把Wireshark开起来。抓包位置一般选在后台主机接入站控层网络的交换机端口上,用端口镜像把装置和后台之间的流量镜像出来。如果条件允许,直接在装置网口和交换机之间串一个物理分光器或小交换机做镜像,能少很多干扰。南瑞继保装置的网络103服务端口常见配置是2404,但不同型号、不同工程可能改成别的端口,抓包前先到装置通讯参数里确认实际端口号,避免抓了半天全是空白。
抓包过滤条件建议直接用TCP端口过滤,例如tcp.port == 2404。不要一上来就抓全量流量,因为变电站站控层网络里往往还跑着IEC104、SNTP、甚至SV和GOOSE相关管理报文,全量抓包会让排查难度翻倍。过滤条件收窄到端口之后,体积小、干扰少,再用tshark导出TCP payload就很快。
抓包时还要注意方向。TCP三次握手中,后台主动向装置的端口发起SYN,后续的SYN-ACK来自装置。看到这个方向关系,后面分析时就能分清哪边是后台、哪边是装置。如果抓包结果里只有后台发出的SYN但一直没人回应,基本是装置侧103服务没有起来或者端口不对。
3.2 写一个最小APDU解析器:处理粘包、半包和0x68定位
解析网络103最靠谱的方式是自己维护一个字节缓冲,把收到的TCP数据不断追加进去,然后循环寻找0x68帧头。找到一个帧头后读取长度字段,判断当前缓冲长度是否够一个完整APDU,不够就继续等待后续数据,够了就切出来解析。下面是这个思路的完整实现。
import os from typing import Optional def decode_time_bytes(tb: bytes) -> str: """按CP56Time2a简化解析,字节序可能因厂家而异,以实际抓包为准。""" if len(tb) < 7: return "" ms = tb[0] | (tb[1] << 8) minute = tb[2] & 0x3F hour = tb[3] & 0x1F day = tb[4] & 0x1F month = tb[5] & 0x0F year = tb[6] return f"{2000 + year:04d}-{month:02d}-{day:02d} {hour:02d}:{minute:02d}:{ms / 1000:.3f}" class Net103Parser: def __init__(self): self.buf = bytearray() self.frames = [] def feed(self, data: bytes): self.buf.extend(data) self._extract() def _extract(self): while True: start = self.buf.find(b"\x68") if start == -1: self.buf.clear() return if start > 0: del self.buf[:start] if len(self.buf) < 2: return length = self.buf[1] total = length + 2 if len(self.buf) < total: return apdu = bytes(self.buf[:total]) del self.buf[:total] parsed = self.parse_apdu(apdu) self.frames.append(parsed) @staticmethod def parse_apdu(apdu: bytes) -> dict: control = apdu[2] asdu = apdu[3:] result = { "control": control, "has_asdu": len(asdu) > 0, "type_id": None, "cot": None, "addr": None, "fun": None, "inf": None, "time": "", } if len(asdu) < 4: return result result["type_id"] = asdu[0] result["cot"] = asdu[2] result["addr"] = asdu[3] if len(asdu) >= 6: result["fun"] = asdu[4] result["inf"] = asdu[5] if len(asdu) >= 7: result["time"] = decode_time_bytes(asdu[-7:]) return result代码的关键逻辑在_extract方法里。每次调用feed后,先在缓冲区里找0x68,找不到就清空缓冲区等待下一批数据。找到0x68且缓冲区长度够两字节时,读取长度字段,算出整帧长度length + 2。这里用len(self.buf) < total判断半包,数据不够就直接返回,等下一批TCP数据来了再继续切分。这样粘包处理也很顺手:一次feed进来多个帧时,while True循环会一直切到缓冲区不足为止。start > 0的清理逻辑很关键,如果缓冲区开头有非0x68的垃圾字节,直接丢弃,避免解析错位。
时间解析函数用的是简化版CP56Time2a字段,把最后7个字节按毫秒、分钟、小时、日、月、年解析。不同厂家对时间字节的顺序可能有差异,南瑞继保的装置报文大多遵循这个布局,但遇到解析结果明显不对时,优先怀疑字节序,不要硬套格式。type_id对应ASDU类型标识,cot是传送原因,addr是公共地址,fun和inf是信号定位的关键字段,time是事件时标。打印一条帧记录时,用control和控制域、type_id和类型标识、fun/inf组合,基本能判断一条报文的来源和含义。
3.3 用tshark导出TCP payload,把抓包文件喂给解析器
Wireshark里手工翻包看细节还行,但报文一多就效率太低。我一般先把pcap导出成hex文本,再交给Python脚本批量解析。tshark导出TCP payload的命令是:
tshark -r capture.pcapng -Y "tcp.port == 2404" -T fields -e data.data > 103_hex.txt这里的-Y是显示过滤,-e data.data把TCP payload转成十六进制字符串输出。每行就是一个TCP报文段的有效载荷,可能是一个完整的APDU,也可能是半个APDU或多个APDU的混合。把这些行逐条喂给解析器即可。
def load_hex_file(filepath: str): parser = Net103Parser() with open(filepath, "r", encoding="utf-8") as f: for line in f: line = line.strip() if not line: continue try: data = bytes.fromhex(line) except ValueError: continue parser.feed(data) return parser.frames frames = load_hex_file("103_hex.txt") for frame in frames: print(frame)导出后跑一遍,脚本会输出所有解析出来的帧,包括控制域、ASDU类型、公共地址、FUN/INF和时间戳。如果某一行单独看长度不够一个APDU,解析器会自动等下一行数据拼上来;如果一行包含多个帧,解析器也会用长度值把它们逐一切开。这就省掉了手工数帧的功夫。
实际跑出来的帧记录看起来是这样的:control=0x09 type_id=1 fun=0x50 inf=0x01 addr=0x0B time=2024-12-01 10:23:45.123。看到type_id=1和fun/inf组合,就可以去对点表里查这个信号对应后台哪个光字牌、哪个遥信点。如果解析出来time字段为空,也不用慌,某些确认帧和链路测试帧本身不带ASDU时标,不参与应用事件判定。
4. 南瑞继保装置接入网络103:参数配置与首轮对点步骤
4.1 装置侧:把保护装置从串口103切到网络103
南瑞继保的PCS系列保护装置,比如PCS-931线路保护、PCS-978变压器保护,站控层通讯口一般都支持网络103规约。接入的第一步是在装置上把通讯规约切到网络103,并配置好IP参数。用装置配套的管理软件连上装置调试网口或面板网口,进入通讯参数菜单,把规约类型改成“网络103”,填写装置IP、子网掩码和网关。IP地址建议在站控层规划网段内设置固定IP,不要用DHCP,否则后台通道会因IP漂移而断链。
服务端口是个关键参数。南瑞继保装置的网络103端口常见默认值是2404,有些装置同时支持103和104时会在不同端口分开监听,具体端口号以装置说明书和实际界面为准。配置完成后保存重启,让规约模块重新初始化。判断规约是否成功起来,一个简单办法是在调试笔记本上跑抓包工具,再让后台去连接装置,观察是否有TCP握手包回应。如果SYN石沉大海,大概率端口没配好或装置规约没有投运。
还要注意一点,老装置的硬件插件可能只有串口103能力,没有以太网口。这种情况要么更换带网络口的通讯插件,要么通过站内通讯管理机做串口转网络转发。判断装置到底支持哪种方式很简单:看装置菜单里有没有“本地IP地址”和“本地端口”配置项,没有基本可以判定这台装置的站控口是串口型的,网络103得走外部设备。
4.2 后台和远动侧:新建网口103通道的关键参数
后台监控系统或远动装置侧,需要新建一个网络103通道。通道参数里填装置IP和装置配置的那个端口号,协议类型选“网络103”,公共地址要和装置侧组态的装置地址一致。这里有个特别容易踩的坑:网络103的公共地址通常是一个字节,和IEC104里的站地址概念不完全一样,别拿104站的两位地址直接填进去,导致装置收到后台总召唤但不识别。
后台还要配置协议运行参数,主要包括总召唤周期、变化上送使能、链路超时时间和遥信去抖时间。总召唤周期典型配置是30秒到60秒,太短会频繁占用装置通讯带宽,太长会导致装置重启后画面长时间空白。链路超时一般设10秒,连续两次超时未收到装置报文才判链路断开。
下面是一张我常用的通道参数参考表,照着填完基本能跑通第一轮:
| 参数 | 典型值 | 说明 |
|---|---|---|
| 装置IP | 192.168.1.10 | 站控层规划网段固定IP |
| 服务端口 | 2404 | 以装置通讯参数界面为准 |
| 协议类型 | 网络103 | 不要误选成串口103 |
| 公共地址 | 0x0B | 与装置组态公共地址一致 |
| 总召唤周期 | 60秒 | 后台周期全量请求 |
| 链路超时 | 10秒 | 连续超时判链路断 |
| 遥信去抖 | 20毫秒 | 滤除触点抖动 |
通道建好后,后台会主动向装置发起TCP连接。此时可以在后台通道监视界面看链路状态,正常应显示在线。如果一直离线,先检查装置IP能不能ping通,再用telnet命令测端口连通性,排除防火墙拦截。注意,后台主机和装置必须在同一网段或路由可达,站控层一般不会跨三层,但遇到过安全接入区ACL把2404端口拦掉的情况,端口可达性测试能快速定位这类问题。
4.3 首轮对点:从链路在线到动作报文验证
链路在线之后不要急着对几百个信号,先从最小集走通。第一步在后台手动触发一次总召唤,看后台画面里这台装置的遥信是否全量刷新。如果全量数据能上来,说明公共地址、类型标识和ASDU基地址解析基本正确。第二步做单点测试:让检修人员到装置面板上模拟一个遥信变位,比如就地遥控分闸或短接一个开入,看后台画面对应点是否在1秒内变位,SOE时标是否准确。
对点的核心是核对FUN/INF映射。拿一台装置的点表,把后台信号描述和装置组态里的功能类型、信息序号逐条比对。下面的点表是示意格式,每个工程的FUN/INF分配都不一样,千万别照抄这个数字去建库:
| 序号 | FUN | INF | 信号描述 | 后台点号 |
|---|---|---|---|---|
| 1 | 0x50 | 0x01 | A相保护动作 | 101YX |
| 2 | 0x50 | 0x0A | 重合闸出口 | 102YX |
| 3 | 0x51 | 0x03 | 断路器合位 | 110YX |
| 4 | 0x51 | 0x04 | 断路器分位 | 111YX |
每次核对通过一个信号,在后台点表里做标记。全部核对完后再做保护动作试验,方法是在装置试验菜单里模拟单相故障,观察后台是否收到动作事件、保护启动、故障测距等多个信号,并且动作时间和装置面板显示时间一致。这里时间偏差跟着时标质量走,网络103通常能保证几十毫秒内的误差。
如果某个信号总是不出来,优先检查是不是FUN/INF配错。可以从后台抓包,看装置上送报文的FUN/INF实际值,和点表对比。经常出现的情况是组态工程师建点表时空行错位,把上一行INF复制到了下一行,这种错只有抓包才能看出来。
4.4 老站改造:串口103平滑过渡到网络103的可行路径
老站改造时,站内通讯管理机往往已经把保护装置的串口103报文转发到了后台。想平滑切到网络103,不需要立刻改每一台装置的通讯方式。常见做法是通讯管理机新增一个网络103通道,把装置的串口103报文从管理机的网口转发出来,后台侧保持原有串口103通道不变,再新开一个网络103通道接管理机的转发口,两个通道并行运行一段时间。等网络103通道的数据和原串口通道完全一致后,再把串口通道退出。
这种方式的好处是装置侧零改动,只需要在通讯管理机和后台侧做配置。风险点是转发口要独占,不能和原有转发通道端口冲突。调试时注意抓包朝向:通讯管理机转发出来的报文已经是网络TCP封装的103,不是纯串口帧,但实际报文内容里可能残留串口帧痕迹,解析脚本要兼容这种形态。我在老站改造项目里会把网络103解析脚本里加上自动剥离0x16结尾的逻辑,能省不少麻烦。
5. 网络103联调避坑指南:五个现场高频踩坑点
5.1 后台报链路断开,但装置IP能ping通
现象是后台监控画面里装置通讯状态变成红色,链路离线,但用ping命令去测装置IP,返回正常。看起来是网络通的却连不上103服务,不少同事第一反应是重启装置,实际没必要。
原因通常是装置的网络103规约模块没有投运,或者TCP监听端口根本没有起来。ping通只能说明IP层可达,不能代表应用层服务在线。另外后台通道的协议如果误选成了IEC104,也会出现TCP连接直接被装置拒掉的情况。
解决方法是先确认装置通讯参数界面里“网络103”开关是否投入,再看端口号是不是后台配的那个端口。用nc命令验证端口连通性,例如nc -vz 192.168.1.10 2404,返回succeeded说明端口通,报Connection refused则说明装置上没有服务在监听。如果端口通但后台还是掉线,抓包看后台发出的TCP SYN有没有得到ACK,有SYN但没有ACK就要检查交换机和防火墙的ACL规则,变电站安全接入区里拦端口的事并不少见。
5.2 遥信变位上送慢,但SOE时标又是对的
现象是检修人员在装置面板上变位一个遥信,后台画面上延迟好几秒才翻红,但SOE报文里的事件时标和装置面板时间一致,分秒不差。很多人因此认为是后台画面刷新慢,忽略了协议层问题。
原因主要是TCP的Nagle算法把多个小报文合并到缓冲区满时才发送,装置每产生一条事件就发一个小帧,结果被算法攒在缓冲区里等后台的ACK,延迟就这么叠出来的。后台侧的延迟确认机制会进一步恶化这个问题。SOE时标之所以准,是因为它是装置在事件发生时打的,和报文到达后台的时间无关。
解决方法是确认后台或装置侧打开了TCP_NODELAY标志,禁用Nagle算法。网络103报文都是小包,实时性要求高,完全不需要Nagle的带宽优化。另外检查后台通道的“变化上送延时”配置,有些后台为防抖默认设置了1到3秒的延时,把它调到100毫秒以内。处理后重新抓包对比,变位报文从装置发出到后台收到的时间应该降到百毫秒级。
5.3 保护动作报文能收到,但故障录波文件拉不下来
现象是保护动作事件、SOE报文都正常上送,后台也收到了动作告警,但故障录波文件列表一直是空的,或者文件拉到一半就断了。这个问题在初次联调时特别常见,很多人会怀疑装置故障录波插件没配,白折腾半天。
原因是网络103的录波文件传输走的是通用分类数据的分组传送机制,一条完整的波形文件被切成多个ASDU分组,后台必须在一段时间内收齐全部分组并做拼装。装置侧上送文件用的等待确认超时和后台侧的接收超时如果设置太短,分组之间稍微有一点延迟超时,整包文件就被判定失败丢掉了。总召唤和录波传输同时发生时,也可能把分组的节奏打断。
解决方法是把后台侧录波文件接收超时调整到30秒以上,保证装置侧有足够时间把所有分组发完。同时确认装置侧“故障数据上送”或“录波文件传输使能”开关打开,很多装置出厂默认关闭这项功能。如果传输总在中途中断,抓包看分组序号是否连续,确认是不是后台在录波传输期间又发了总召唤把链路资源抢走,可以临时把总召唤周期调长或者暂停总召,等文件收完再恢复。
5.4 装置重启后后台画面全黑,必须手动总召一次才能恢复
现象是保护装置因为检修断电重启,TCP链路自动恢复在线,后台通道显示正常,但遥信画面一片空白,没有任何数据变化。手动在后台触发一次总召唤之后,所有数据瞬间就上来了。
原因是TCP链路恢复不等于应用层数据同步。装置重启后,后台侧没有装置当前状态的任何缓存,而装置在重启后不会主动把全量状态再发一遍,它只在状态发生变化时触发变化上送。没有变化就没有报文,后台和装置都觉得链路是通的,但数据就是缺的。这就是网络103总召唤机制必须存在的根本原因。
解决方法是确认后台通道配置了“链路重连后自动总召唤”选项,把它打开。如果后台没有这个选项,就把总召唤周期设成30到60秒,用周期总召兜底。还要检查装置侧上电后的总召唤等待参数,有些装置允许配置上电后多长时间内接受首次总召唤,这个值如果配成0会导致后台总召发出后被忽略。我一般在调试配好后的第一件事就是重启装置,验证后台能否自动恢复全量数据,这一步过了才敢继续往下做其他对点。
5.5 抓包解析时报长度字段非法,或解析出乱码
现象是拿自己的解析脚本去跑抓包文件,经常解析出长度几百字节的异常APDU,或者某些帧解析出来的字段值完全不符合常识。这种情况往往不是脚本写错了,而是抓的流量混入了非103报文。
原因主要有三个可能:一是过滤条件没有对准端口,把IEC104、MMS之类的帧也抓进来了;二是现场通过串口服务器转换,TCP payload里残留了串口帧头0x10、帧尾0x16和校验字节;三是后台主机上还有其他进程在访问装置的非103服务端口,产生混合流量。
解决方法是严格按端口过滤重新抓包,导出TCP payload时用tshark确认一下数据格式。解析器里增加合法性校验:帧头必须是0x68,长度字段不要超过200,长度字段加2不能超过当前缓冲剩余字节数。这样即使混入了垃圾字节,解析器也能通过0x68定位重新同步,不会让一个坏帧废掉整段缓冲。我在解析器里加过一条经验值:如果连续三次在找到一个0x68帧头但随后长度校验失败,就丢弃这个0x68并继续向后搜索,这种容错逻辑能让脚本在网络环境复杂的老站里稳定不少。
6. 进阶:用报文注入做联动验证,别等下一次真实故障
对点完成不等于万事大吉。监控后台的告警联动逻辑,比如事故总信号、光字牌弹窗、音响启动,往往要等真实故障才会触发验证。但真实故障不可控,等它来验证逻辑效率太低。更靠谱的做法是把抓到的真实动作报文改一下时标,重新注入后台,验证后台的反应行为。这样做不会改变报文长度,TCP序列号和ACK都不用重算,链路不会因为序列号错乱被断开,技术风险很小。
注入的原理是先做一个监听端口的脚本,让脚本代替装置等待后台TCP连接。后台通道的IP指向这个脚本所在机器,端口保持和原装置一致,脚本收到后台连接后,把抓包导出的真实动作报文发给后台。报文的ASDU内部时标字段修改一个字节,后台会把它当成一条新事件处理。这样可以在几分钟内验证后台是否能正确弹告警、SOE排序是否正确、重复事件会不会被去重。
import socket SRV_IP = "0.0.0.0" SRV_PORT = 2404 # 从抓包里取一条真实保护动作报文的hex,例如: # 6809 09 01 01 01 0B 50 01 00 01 02 03 ... raw = bytes.fromhex("6809090101010B5001000102030405") srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) srv.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) srv.bind((SRV_IP, SRV_PORT)) srv.listen(1) conn, addr = srv.accept() # 等待后台总召唤后,把修改时标的报文发过去 conn.send(raw) conn.close()这段脚本的核心点是TCP_NODELAY必须打开,否则注入报文可能被Nagle算法延迟,验证结果就不真实了。改时标时只改一个字节,比如把ASDU时标里的毫秒低位从0x04改成0x05,报文总长度不变,TCP层完全无感。多跑几轮,把不同动作信号的FUN/INF轮换注入一遍,就能验证后台每一个告警联动分支。
这些年接过不少网络103的现场,回头看,最省心的调试顺序永远是先把抓包和解析工具准备好,再确认公共地址和端口,最后才是对点表。顺序一旦反过来,链路不通时对着点表干瞪眼,白白消耗现场时间。希望这套把报文拆开、把参数理清、把注入工具备好的方法,能让你在下一个站里少加班几个晚上。
本文还有配套的精品资源,点击获取