news 2026/9/17 13:30:37

IEC104规约报文解析:APCI/ASDU结构、Wireshark抓包与故障排查

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
IEC104规约报文解析:APCI/ASDU结构、Wireshark抓包与故障排查

简介:在电力远动通信系统中,规约报文是设备间数据传输的载体,工程师常需通过抓包定位异常。IEC104规约作为运行于TCP之上的应用层协议,其报文由APCI和ASDU构成:APCI负责会话控制与序号管理,ASDU承载遥测、遥信等业务数据。掌握APDU边界识别、I帧序号计算、类型标识与传送原因的含义,是解析报文的基础。借助Wireshark等工具,可快速完成U帧握手确认、总召唤流程跟踪及数据完整性校验,从而在远动通道调试中高效排查握手失败、序号跳变等典型故障。本文面向远动通信与电力自动化运维场景,结合抓包实践讲解IEC104报文结构、常用字段及故障定位思路,适合需要开展点表映射、规约调试与网络分析的工程师参考。

1. IEC104规约报文分析:看得懂十六进制,对不上业务才是真门槛

凌晨两点调度电话把值班工程师叫醒:主站侧看着TCP连接是通的,变电站侧就是不上数据。抓包出来几十条重复的STARTDT激活帧,通道参数、IP地址、端口查过一遍,最后发现是站端装置应用层没起来。这是IEC104规约报文分析里非常典型的一个坎:104规约跑在TCP上,控制信息在APCI里,业务数据在ASDU里,和串口时代的101规约完全不同。看懂IEC104报文,关键不是逐字节翻译十六进制,而是把U帧握手、I帧序号和ASDU里的类型标识、传送原因、信息对象地址对应到远动点表上。下面按这条线拆开讲,覆盖APCI与ASDU结构、常用类型标识、用Wireshark从抓包到解析的流程,以及现场常用的排障技巧,适合刚接手远动通道调试、准备写点表映射脚本的工程师。

2. IEC104规约报文先分层:端口2404、APCI控制域和帧类型

2.1 一条104报文由APCI和ASDU组成

IEC104规约在IEC 60870-5-104标准里定义,应用层直接跑在TCP之上,默认端口2404。一个TCP连接可以双向传输报文,报文的基本单位叫APDU(应用规约数据单元),结构分两段:前6字节是APCI(应用规约控制信息),后面是ASDU(应用服务数据单元)。APCI包含启动字符0x68、APDU长度、4字节控制域;ASDU承载遥测、遥信、遥控等具体业务。

这里有个容易误解的地方:APDU和TCP报文段不是一回事。APDU的边界由第2个字节的长度字段确定,比如0x68 0x10表示后面还有16字节,整条APDU共18字节。不管TCP层怎么分片、粘包,解析器都靠这个长度字段把APDU一条条切出来,而不是靠回车换行或固定超时。一条APDU最长253字节,其中ASDU最多249字节,比串口101规约的单帧容量大很多,这也是104能批量上送几十个点的主要原因。

平时说的“104报文分析”,绝大多数场景是在抓包里把APDU边界划对,再看控制域和ASDU。APDU长度对不上时,Wireshark会显示“malformed packet”,先查抓包是不是超过MTU后被拆开,或者TCP流重组没打开。

2.2 四字节控制域:I帧、S帧、U帧的区别与报文值

控制域的4字节是整个会话状态机的核心。前2比特标识帧类型:I帧是信息帧,低2位为00;S帧是监视帧,低2位为01;U帧是控制帧,低2位为11。I帧带双向序号,S帧只带接收序号,U帧不带序号。

帧类型判定位携带序号典型作用常见报文示例
I帧bit0=0,bit1=0N(S)和N(R)携带ASDU业务数据68 10 08 00 08 00 ...
S帧bit0=1,bit1=0仅N(R)纯确认,不携带ASDU68 04 01 00 02 00
U帧bit0=1,bit1=1启动/停止数据传输、测试链路68 04 07 00 00 00

I帧的发送序号N(S)和接收序号N(R)各占15位,从0递增,到32767后回绕。序号从字节里取出来时要注意位偏移:N(S)是第1字节bit1到bit7拼接第2字节共15位,N(R)是第3字节bit1到bit7拼接第4字节共15位。换算公式为:

N(S) = ((b0 >> 1) & 0x7F) | (b1 << 7) N(R) = ((b2 >> 1) & 0x7F) | (b3 << 7)

其中b0到b3是控制域4字节。这个位运算很多解析脚本里都会出现,写错会导致看到的序号跳变,进而误判丢包。

U帧没有序号,它的4字节控制域只有第1字节有意义,第2到第4字节为0。现场最常遇到的U帧报文是这几个:STARTDT act(主站请求数据传输)为68 04 07 00 00 00,STARTDT con(从站确认)为68 04 0B 00 00 00;STOPDT act为68 04 13 00 00 00,STOPDT con为68 04 23 00 00 00;TESTFR act为68 04 43 00 00 00,TESTFR con为68 04 83 00 00 00。记不住位定义没关系,记这几个十六进制值就能应付绝大多数抓包场景。

TCP连接建立后,主站必须先发STARTDT act,从站回STARTDT con,此时才允许传I帧。如果抓包里只有TCP三次握手和不断重复的STARTDT act,基本可以断定从站应用层没有正常启动或网关配置错误,而不是链路问题。

2.3 与101规约、61850通讯规约的边界

很多刚接触的人会把104规约和101规约混在一起。101规约走串口或低速网络,帧格式是FT1.2,有起始字符、控制域、地址域、用户数据、校验和,一帧最多255字节;104规约是101规约在TCP/IP网络上的改造,应用层的ASDU沿用了101的定义,但链路层换成APCI加TCP。也就是说,ASDU字段两边基本通用,APCI和帧格式完全不通用。

站内通信则更多遇到61850通讯规约。61850用于变电站站控层和间隔层之间的MMS、GOOSE、SV报文,解决的是站内设备互操作;104规约解决的是变电站与调度主站之间的远动信息传输,两者在链路层面没有交集,但调试时经常同时出现:同一个测控装置既上送104到主站,又在站内跑61850,点表对不上时要从两端分别找原因。

另外还要注意,698规约和DL/T 645-1997是用电信息采集方向的内容,面向电能表计费数据,报文格式跟远动的104完全不同,别拿104的解析思路往那上面套。

3. ASDU字段拆解:类型标识、传送原因和公共地址决定怎么解析

3.1 ASDU头部字段逐个看

ASDU从类型标识开始,一个完整的ASDU由固定头和信息对象组成。固定头依次是:类型标识1字节、可变结构限定词(VSQ)1字节、传送原因1字节、公共地址2字节。信息对象部分根据类型标识的不同而变化,可能包含多个信息对象,每个对象有信息对象地址(IOA)和对应的数据体。

类型标识告诉解析器后面跟的是什么数据:是单点遥信、双点遥信、短浮点遥测、还是遥控命令。这个字节不认对,后面全是错的。可变结构限定词的bit7是连续标志,低7位是信息对象个数;如果连续标志为1,表示这组信息对象的地址是连续的,报文里只写第一个地址,后面依次加1;如果为0,每个对象都带完整地址,报文会明显变长。

传送原因占1字节,bit6是测试标志(S/E位),低6位是原因值。现场看到0x43、0x47这类值,先转成二进制,bit6为1表示这是测试链路时发的报文,不是真实数据。公共地址占2字节,小端存储,用于区分不同厂站,一个TCP连接上一般固定为一个值,跨厂站共用通道时尤其要注意。

3.2 现场最常用的类型标识与传送原因

IEC104规约的类型标识沿用了101规约的定义,真正天天用的就几个。以下是调试远动通道时最常遇到的类型:

类型标识十六进制名称信息对象内容
10x01单点遥信 M_SP_NA-11字节,bit0为分合状态
30x03双点遥信 M_DP_NA-11字节,bit0/bit1组合
90x09带时标的单点遥信 M_SP_TB-1状态1字节加7字节时标
130x0D短浮点遥测 M_ME_NC-14字节IEEE754浮点加1字节品质
450x2D单点遥控 C_SC_NA-11字节命令,含选择执行标志
460x2E双点遥控 C_DC_NA-11字节命令
1000x64总召唤 C_IC_NA-1信息对象地址一般为0
1030x67时钟同步 C_CS_NA-17字节CP56Time2a时标

传送原因最常用的是这几个:1表示周期上送,2表示背景扫描,3表示突发上送,5表示请求,6表示激活,7表示激活确认,8表示停止激活,10表示激活终止,20表示响应站召唤。排查“丢数据”问题时,先看原因:周期上送的数据丢了可能是扫描周期配置问题,突发上送的丢了则要查事件缓存和确认机制。

3.3 手工拆一条短浮点遥测报文

拿一条实际报文来看完整拆解过程。假设抓包得到如下帧:

68 11 08 00 08 00 0D 01 03 01 00 00 00 00 00 00 C8 42 00

第1字节0x68是启动字符,第2字节0x11表示APDU长度17,后面跟着4字节控制域和13字节ASDU。控制域08 00 08 00是I帧,N(S)=4,N(R)=4,说明双方序号正常连续。ASDU部分逐字节看:

  • 0x0D,类型标识13,短浮点遥测;
  • 0x01,VSQ,bit7为0,1个信息对象;
  • 0x03,传送原因,突发上送;
  • 0x01 0x00,公共地址小端为1;
  • 0x00 0x00 0x00,信息对象地址为0;
  • 0x00 0x00 0xC8 0x42,IEEE754短浮点,低字节在前,实际值是0x42C80000;
  • 0x00,品质描述字节,正常值。

0x42C80000按IEEE754转换,得到100.0。这条报文表达的是:1号厂站第0点遥测值100.0,突变上送,数据有效。如果点表里第0点是有功功率,单位MW,那这条报文就是“有功100MW变位上送”。

3.4 信息对象地址与CP56Time2a时标的坑

信息对象地址在104规约里是3字节小端,范围最大到0xFFFFFF,厂站点表通常按这个值映射。调试时最常见的坑是:主站点表和厂站点表对不上,主站看IOA=256,厂站侧却从1开始编号。抓包只能看到IOA原始值,对点必须拿厂站点表来核对,不能按报文里的数字猜含义。

带时标的信息对象,时标固定7字节,格式是CP56Time2a:前2字节是毫秒(低字节在前),后面依次是分、时、日、月、年各1字节。比如某条带时标遥信的时标字段为00 00 05 0D 19 02 0B,表示毫秒0、分钟5、小时13、日25、月2、年11,即2011年2月25日13时5分0秒。注意年份是偏移表示,0对应2000年,所以0x0B要按2011年来读。写解析脚本时,年、月、日这几个字段都要加偏移和校验,否则排序会乱。

4. 用Wireshark分析104报文:从U帧握手到总召唤数据上送

4.1 抓包过滤与解码视图

Wireshark从2.x版本起内置了IEC 60870-5-104解码器,不需要额外装插件。抓包时建议在采集点用主机镜像端口或TAP,避免在应用层设备上抓导致报文已经被改写。打开抓包文件后,先过滤:

tshark -r capture.pcapng -Y "tcp.port == 2404" -c 20

这条命令用tshark从抓包文件里筛出前20条与2404端口相关的报文。参数-r指定输入文件,-Y是显示过滤器,-c限制输出条数。在Wireshark图形界面里,显示过滤器输入tcp.port == 2404,可以排除其他端口干扰;如果想只看已被识别为104的帧,可以输入iec60870_5_104,但要注意只有解码器成功识别APDU时才会带上这个协议名,TCP握手包不会出现。

4.2 一次完整总召唤的报文序列

新站接入调试时,第一个要看的就是总召唤流程。正常顺序如下:

  1. TCP三次握手建立连接;
  2. 主站发U帧STARTDT act,从站回STARTDT con;
  3. 主站发I帧总召唤,传送原因6(激活);
  4. 从站回总召唤确认,传送原因7(激活确认);
  5. 从站批量上送全数据,包括遥信、遥测;
  6. 全部上送完,从站发总召唤结束,传送原因10(激活终止)。

对应抓包里的报文轮廓是:

方向报文含义
主站 → 从站68 04 07 00 00 00STARTDT act
从站 → 主站68 04 0B 00 00 00STARTDT con
主站 → 从站68 0C 00 00 00 00 64 01 06 01 00 00 00 00总召唤,原因6
从站 → 主站68 0C 00 00 02 00 64 01 07 01 00 00 00 00总召唤确认,原因7
从站 → 主站68 11 02 00 02 00 0D 01 03 01 00 00 00 00 00 00 C8 42 00遥测上送,值100.0
从站 → 主站68 0C 04 00 02 00 64 01 0A 01 00 00 00 00总召唤结束,原因10

注意控制域里序号的连续性:主站的总召唤N(S)=0,从站的确认N(S)=0且N(R)=1表示已收到主站第0帧;后续数据帧N(S)逐步加1。如果中间某帧序号跳了,说明有I帧丢失,重传机制会触发,但总召唤流程会变慢。

4.3 在Wireshark里核对一条遥测I帧

选中一条I帧,在Packet Details面板展开“IEC 60870-5-104 APDU”,能看到APCI和ASDU两个子树。APCI里显示帧类型、发送序号、接收序号;ASDU里显示类型标识、可变结构限定词、传送原因、公共地址、信息对象地址和数值。以4.2中那条68 11开头的报文为例,树形展开后应显示:Type Identification=13,VSQ=1个不连续对象,Cause=3,Common Address=1,IOA=0,State=100.0。

这里建议把列显示调一下:右键控制域里的“Send Sequence Number”,选择“Apply as Column”,把所有I帧序号按列排列,方便快速扫一遍序号是否连续。总召唤后的数据量大时,用这个方式排查漏帧比逐帧点开高效得多。

4.4 TCP分片、乱序对104解码的影响

104报文最长253字节,远小于TCP的MSS(通常1460字节),正常不会因为长度产生分片。但抓包时如果开了巨型帧,或者中间有TCP透明代理改了报文,反而会出现一条APDU被拆到多个TCP段的情况。Wireshark默认会重组TCP流,但如果抓包不完整,重组失败就可能把后续报文全部标成malformed。

遇到乱序或重传时,不要直接在104解码视图里下结论。先切换到Follow TCP Stream看原始数据,再对照长度字段手工切分APDU。重传的TCP段会带“TCP Retransmission”提示,对应的104报文是重复的I帧,这时要检查是网络丢包还是对端确认超时,而不是数据本身出错。

5. 104故障定位实践:握不上、序号跳变和一段解析脚本

5.1 握手失败先分清TCP和应用层

主站收不到数据时,第一抓包看TCP握手是否完成。如果SYN都发不出去,问题在路由、防火墙或端口策略,典型原因是2404端口未放通。TCP握手正常但看不到STARTDT act,主站侧应用可能没启动。看到STARTDT act反复发、始终没有STARTDT con,问题在从站侧应用层:装置未运行、规约版本不匹配、或者从站收到act后认为配置未就绪不回应。此时再查从站的运行日志而不是继续抓主站。

5.2 序号连续性检查

序号跳变是丢包最直接的信号。用Wireshark把I帧N(S)排成列后,逐行检查差值是否等于1。如果出现跳号,接着看跳号前是否有TCP重传或乱序标记;如果没有,说明报文在中间设备上被丢弃,需要检查交换机端口丢包统计和防火墙会话表老化时间。还有一种情况是序号回绕,15位计数器到32767后归零,这是正常现象,不要当跳变处理。

5.3 Python小脚本:自动核对I帧序号和字段

现场报文量大时,手工核对不现实。把抓包导出的十六进制逐条喂给下面这个脚本,它能自动输出I帧序号和关键字段:

import sys def parse_apdu(line: str): data = bytes.fromhex(line.strip()) if len(data) < 6 or data[0] != 0x68: return None apdu_len = data[1] body = data[2:2 + apdu_len] if len(body) < 6: return None ctrl = body[:4] # 低2位为00表示I帧 if (ctrl[0] & 0x03) != 0: return {"frame": "U或S帧"} ns = ((ctrl[0] >> 1) & 0x7F) | (ctrl[1] << 7) nr = ((ctrl[2] >> 1) & 0x7F) | (ctrl[3] << 7) return { "ns": ns, "nr": nr, "type_id": body[4], "is_continuous": bool(body[5] >> 7), "count": body[5] & 0x7F, "cause": body[6] & 0x3F, "common_addr": int.from_bytes(body[7:9], "little"), } for line in sys.stdin: line = line.strip() if not line: continue p = parse_apdu(line) if p and "ns" in p: print(f"ns={p['ns']:5d} nr={p['nr']:5d} " f"type=0x{p['type_id']:02x} cause={p['cause']:3d} " f"addr={p['common_addr']} count={p['count']}")

脚本先校验启动字符和长度字段,然后只处理I帧,U帧和S帧跳过。ns和nr按APCI的15位序号格式从字节里拼出来,type_id是类型标识,cause是传送原因。count是可变结构限定词里的对象个数。把抓包工具导出的十六进制文本重定向到脚本输入,输出里如果ns不再连续递增,就是丢包位置;如果type_id里混进预想之外的类型,再去抓包里定位具体那条帧。把跳变帧前后各20条报文再导出来比对发送间隔,就能定位是网络丢包还是对端重传。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 13:28:12

Excel表格秒变LaTeX代码:excel2latex插件安装配置与使用全指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 13:27:50

告别PPT导出模糊,高清无损图片导出方法全解析

说实话&#xff0c;用 PPT 画图这事儿&#xff0c;入坑之后是真的香——论文配图、教程截图、公众号头图、甚至临时拼个海报&#xff0c;我都拿它搞定。但几乎每个人第一次把 PPT 里的内容导出成图片时&#xff0c;都会被默认那张“糊图”气到&#xff1a;屏幕上明明挺锐利&…

作者头像 李华
网站建设 2026/9/17 13:27:20

图书管理系统课程设计全解析:软工流程与SQL实现

简介&#xff1a;《图书管理系统&#xff08;软件工程课程设计报告&#xff09;》是一份面向软件工程专业学生与课程设计团队的完整项目文档&#xff0c;以XX学院09信计开发小组的图书管理系统项目为实例&#xff0c;系统说明了可行性研究、项目开发计划、需求分析、总体设计等…

作者头像 李华
网站建设 2026/9/17 13:26:00

GitHub入门实战:从本地项目上传到日常同步的完整指南

1. 先弄明白GitHub和Git&#xff0c;再开始动手1.1 一句话讲清Git和GitHub的关系很多新手会把Git和GitHub当成一回事&#xff0c;其实它们是两样完全不同的东西。Git是一个在你电脑本地运行的版本管理工具&#xff0c;负责记录代码每一次的改动&#xff0c;相当于一个细到文件行…

作者头像 李华
网站建设 2026/9/17 13:25:51

Android大作业新闻App开发与实验报告撰写指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华