1. 项目概述从“黑话”到“普通话”的工业通信桥梁如果你在电力自动化、工业控制或者智能变电站领域摸爬滚打过一定对“104规约”这个词不陌生。它就像这个圈子里的“黑话”老工程师们提起来心领神会但新人听到往往一头雾水。今天我就以一个干了十几年电力通信调试的老兵身份把这套“黑话”掰开揉碎了翻译成大家都能听懂的“普通话”聊聊这个在电网调度自动化里扮演着“中枢神经”角色的通信协议。简单来说IEC 60870-5-104规约我们习惯简称为104规约是电力系统里用来实现调度主站比如省调、地调中心和远方变电站内的自动化设备比如远动装置、综合自动化系统之间进行“对话”的一套标准语言。它的核心任务就是把变电站里五花八门的实时数据——比如哪个开关跳闸了遥信、线路电流有多大遥测、变压器档位在哪儿遥调——准确、及时、有序地“告诉”几十甚至几百公里外的调度员。同时调度员也能通过这套语言远程对变电站的设备下发控制命令遥控。可以说没有这套稳定可靠的通信规约现代的电网调度和自动化就是一句空话。我最早接触104规约是在十多年前的一个老旧站改造项目上当时为了打通主站和子站的通信对着厚厚的协议文档和满屏的十六进制报文抓耳挠腮。踩过无数坑之后才明白理解104规约关键不在于死记硬背那些枯燥的帧格式而在于理解它设计背后的逻辑如何在不可靠的TCP/IP网络之上构建一套可靠、高效、面向连接的问答机制。这篇文章我会结合大量的实操案例和报文解析带你深入104规约的“五脏六腑”无论你是刚入行的调试工程师、负责系统集成的研发人员还是需要对自动化系统进行运维管理的技术人员都能从中找到直接能用的“干货”和“避坑指南”。2. 104规约的整体架构与设计哲学2.1 核心定位TCP/IP上的远动“专线”在深入细节之前我们必须先建立对104规约的整体认知。它不是一个凭空创造的全新协议而是站在巨人的肩膀上。这个“巨人”就是IEC 60870-5-101规约常称101规约一套在串行链路如RS-485上运行得非常成熟的远动协议。101规约定义了丰富的数据类型和传输规则但其物理层依赖串口传输距离和速率受限。104规约的诞生就是为了解决这个问题。它的全称是“IEC 60870-5-101的网络访问”本质上104 101的应用层 TCP/IP的传输/网络层。你可以把它想象成把101规约这封写好的“信”装进TCP/IP这个标准“快递信封”里通过以太网这条“高速公路”寄出去。这样的设计带来了几个根本性的优势突破距离限制依托于成熟的TCP/IP网络可以是电力专网也可以是经过安全隔离的调度数据网通信距离从串口的千米级扩展到网络可达的任何地方。提高传输效率网络带宽远高于串口使得大量数据如全站遥信、遥测的周期性上送和突发事件如事故总信号的快速响应成为可能。连接管理标准化直接利用TCP协议提供的面向连接、可靠传输的特性省去了101规约中复杂的链路层维护机制如帧校验、超时重发让规约设计更专注于应用层的数据交互。注意虽然底层用了TCP但104规约的应用层自己又定义了一套完整的确认机制。这是因为TCP只保证字节流不错、不漏、不乱序地送到但不管送的内容应用报文是否被对方正确理解和处理。所以104规约在TCP的可靠传输之上又叠加了一层应用层的“可靠对话”机制。2.2 通信角色与连接模式在104规约的世界里通信双方有明确的角色划分控制站Control Station通常指调度主站或集控中心。它是通信的发起者和主导者负责初始化连接、召唤数据、下发控制命令。被控站Controlled Station通常指变电站内的远动终端RTU或综合自动化系统。它响应控制站的请求主动或被动地上送数据。它们的连接模式非常固定被控站作为TCP服务端Server监听一个固定端口默认2404控制站作为TCP客户端Client主动向被控站的IP和端口发起连接。这种C/S架构清晰、稳定符合调度系统“中心主动、厂站被动响应”的业务逻辑。在实际项目中一个常见的“坑”就在这里。有些自动化设备厂家默认的服务端口可能不是2404或者厂站侧的防火墙策略没有开放该端口会导致控制站始终无法建立TCP连接。我的经验是上站调试前务必先和厂站运维人员确认网络可达性用笔记本电脑ping和telnet测试端口这能节省大量无谓的排查时间。2.3 报文结构总览APDU与三种帧类型104规约的所有对话都封装在一条条“应用协议数据单元APDU”中。每条APDU由两部分组成启动字符Start Byte, 68H固定为0x68标识一条104报文的开始。应用规约数据单元APDU长度一个字节表示后续从该字节之后到报文结束的字节数。注意这个长度值必须小于等于2530xFD这是协议规定的上限。应用服务数据单元ASDU这是报文的“正文”包含了真正的控制信息和数据内容。而根据APDU承载的功能不同104规约的报文可以分为三大类型理解这三类报文是掌握104通信逻辑的钥匙I格式帧信息传输格式这是承载“干货”的报文。无论是厂站上送的遥信、遥测数据还是主站下发的遥控、遥调命令都用I帧来传送。I帧是唯一需要进行编号和确认的帧这是实现应用层可靠传输的核心。S格式帧确认格式这是一种“已读回执”。当接收方正确收到一批I帧后可以发送一个S帧告诉对方“你发到编号XXX为止的I帧我都收到了。” S帧本身不携带数据只负责确认可以有效减少网络流量避免对每一个I帧都进行确认的繁琐。U格式帧控制格式这是一种“管理指令”用于建立、维护和拆除应用层的连接注意不是TCP连接。它不携带ASDU也不参与编号。主要有三种STARTDT启动数据传输连接建立后由控制站发送询问被控站“我可以开始传数据了吗”被控站回复同样的STARTDT表示同意。只有成功交换STARTDT后双方才能开始传输I帧和S帧这是104规约应用层连接建立的标志。STOPDT停止数据传输由控制站发送通知被控站“我暂时不想收数据了。”被控站确认后将停止发送I帧。TESTFR测试帧当通信双方长时间没有数据交互时为防止TCP连接被中间网络设备因超时而断开会周期性地发送TESTFR帧相当于说“嗨我还活着链接别断。”3. 核心机制深度解析编号、确认与平衡传输3.1 发送/接收序号V_S, V_R与滑动窗口这是104规约最精妙也最容易出问题的部分。为了实现应用层的可靠传输每一个I帧都带有两个序号发送序号Send Sequence Number, N(S)发送方为当前发出的I帧分配的编号。接收序号Receive Sequence Number, N(R)发送方通过这个编号来确认对方发来的I帧。它的含义是“我期望收到的下一个I帧的序号”。换句话说N(R) - 1 就是发送方已经正确收到的、来自对方的最大I帧序号。每个通信端都维护着两个关键的计数器V_S发送状态变量本地下一个将要发送的I帧的序号。每发送一个I帧V_S加1。V_R接收状态变量本地期望接收到的下一个I帧的序号。每正确接收一个顺序正确的I帧V_R加1。滑动窗口机制协议规定未经确认的I帧不能无限制地发送。它通过一个“窗口”来限制。通常发送窗口大小W默认为12可配置。发送方最多能连续发送从V_S到V_SW-1序号范围内的I帧。只有收到对方确认通过S帧或对方I帧中的N(R)后窗口才会向前滑动释放出新的序号用于发送。实操中的典型问题序号溢出。V_S和V_R是16位无符号整数范围0-65535。当序号增加到65535后下一个序号会回绕到0。如果通信双方对序号回绕的处理逻辑不一致就会导致通信中断。质量好的设备会正确处理回绕而一些老旧或设计有缺陷的设备可能会在此处“卡死”。在长周期运行的系统中这是一个需要关注的潜在风险点。3.2 平衡式与非平衡式传输这是104规约两种根本不同的数据传输模式决定了通信的“节奏”由谁掌控。非平衡传输Unbalanced这是最经典、最常用的模式。在这种模式下控制站是绝对的“主人”被控站是“仆人”。所有数据的传输都由控制站发起通过发送“总召唤GI”命令被控站才将全部数据打包上送通过发送“召唤单点单双点信息”等命令被控站才上传变化数据。这种模式逻辑清晰主站压力小但实时性稍差尤其对于需要快速响应的突发事件如开关变位。平衡传输Balanced在这种模式下双方地位更加平等。被控站无需等待主站的召唤命令就可以主动上送变化信息如突发遥信变位。这极大地提高了事件报告的实时性。当然控制站仍然可以下发召唤命令和遥控命令。平衡传输对双方的处理能力要求更高且需要更完善的流量控制机制防止被控站突发大量数据淹没主站。如何选择在早期的变电站和县级调度中非平衡传输是主流简单可靠。而在智能变电站、要求事件快速上报如故障录波触发、保护动作信号的高级应用场景以及IEC 61850体系下与104规约的配合中平衡传输的应用越来越广泛。在工程配置时务必确认主站和子站设备是否支持以及配置了同一种传输模式否则通信无法建立。3.3 ASDU结构信息对象的“集装箱”ASDU是I帧的“货物”它本身也是一个结构化的数据单元。理解ASDU的结构就能看懂104规约到底传输了什么。其结构如下类型标识Type Identification, 1字节定义这条ASDU携带的是什么类型的数据。这是解析报文的第一把钥匙。常见的有0x01(M_SP_NA): 单点遥信信息不带时标0x03(M_DP_NA): 双点遥信信息不带时标0x09(M_ME_NA): 测量值规一化值遥测0x2E(M_ME_TF): 带CP56Time2a时标的测量值0x2D(C_SC_NA): 单点遥控命令0x64(C_IC_NA): 总召唤命令0x65(C_CI_NA): 电能脉冲召唤命令可变结构限定词VSQ, 1字节最高位表示信息对象的组织方式0一个ASDU内只有一个信息对象地址1一个ASDU内有多个连续的信息对象地址。低7位表示信息对象的数量。例如VSQ0x81表示有1个信息对象且是单地址VSQ0x07表示有7个连续地址的信息对象。传送原因Cause of Transmission, COT, 1或2字节定义为什么要发送这个ASDU。这是解析报文的第二把钥匙对于分析通信行为至关重要。常见原因有0x01: 周期/循环0x03: 突发自发0x04: 初始化0x05: 请求或被请求响应总召唤0x06: 激活命令下发0x07: 激活确认命令被接收0x0A: 激活终止命令执行完成0x2D: 未知的类型标识0x2E: 未知的传送原因0x2F: 未知的ASDU公共地址0x3C: 未知的信息对象地址公共地址Common Address, 1或2字节标识这个ASDU来自于哪个被控站RTU地址。通常与远动装置的站地址一致。信息对象Information Object真正的数据载荷由一个或多个“信息对象体”组成。每个信息对象体至少包含信息对象地址IOA, 3字节这是第三把钥匙也是最重要的钥匙。它唯一标识了变电站内的一个具体数据点比如“101号开关的A相位置”、“205号线路的有功功率”。主站和子站的数据库必须对IOA的定义完全一致否则就会出现“张冠李戴”——主站看到开关跳闸实际可能是变压器温度越限。信息元素Information Elements数据值本身如一个字节的单点状态0x01分0x02合、四个字节的浮点数遥测值、七个字节的时标等。时标Timestamp可选当类型标识指明带时标时存在格式为CP56Time2a7字节精确到毫秒。4. 典型通信流程与报文解析实战光说不练假把式。下面我们通过Wireshark抓取的真实报文已做脱敏处理来还原一个完整的104规约通信会话。假设主站地址为10.10.10.1子站地址为10.10.10.100监听端口2404。4.1 连接建立与总召唤初始化TCP三次握手10.10.10.1:55000 - 10.10.10.100:2404 [SYN] 10.10.10.100:2404 - 10.10.10.1:55000 [SYN, ACK] 10.10.10.1:55000 - 10.10.10.100:2404 [ACK]TCP连接建立成功。U帧启动数据传输STARTDT主站发送68 04 07 00 00 0068: 启动字符。04: 后续长度4字节。07 00 00 00: U帧控制域。07转换为二进制0000 0111最低三位111表示这是一个STARTDT ACT启动数据传输激活命令。子站回复68 04 0B 00 00 000B转换为二进制0000 1011最低三位011表示这是一个STARTDT CON启动数据传输确认。至此应用层连接建立可以开始传输I帧。I帧总召唤命令C_IC_NA主站发送68 0E 00 00 00 00 64 01 06 00 01 00 00 00 00 00 1468 0E ...: 启动字符和长度14字节。00 00 00 00: I帧控制域。前两个字节00 00是发送序号N(S)0后两个字节00 00是接收序号N(R)0。这是连接建立后的第一个I帧。64: 类型标识0x64代表“总召唤命令”。01: VSQ0x01表示1个信息对象单地址。06 00: 传送原因0x0006表示“激活”。01 00: 公共地址0x0001站地址1。00 00 00: 信息对象地址IOA0x000000总召唤通常地址为0。00: 限定词QOI0x00一般总召唤。14: 召唤范围0x1420可能代表召唤20号组的数据具体含义取决于双方约定。I帧总召唤确认C_IC_NA子站回复68 0E 00 00 02 00 64 01 07 00 01 00 00 00 00 00 14发送序号N(S)0接收序号N(R)2。N(R)2意味着子站已经正确收到了主站发送的序号为0和1的I帧目前只发了序号0的总召唤序号1的帧可能是一个时钟同步命令这里省略了。类型标识64传送原因变为07 000x0007表示“激活确认”。其他字段与命令帧一致。这表示子站接受了总召唤任务。4.2 子站上送数据与S帧确认I帧遥测数据上送M_ME_NA子站发送68 16 02 00 02 00 09 01 05 00 01 00 01 00 00 40 20 00 00 02 00 00 80 28 00 00N(S)2, N(R)2。09: 类型标识0x09规一化测量值。01: VSQ0x011个信息对象本例中VSQ0x81更常见表示单点信息对象。这里可能是简化表示或特定厂商实现我们按一个对象解析。05 00: 传送原因0x0005“请求或被请求”即响应总召唤。01 00: 公共地址1。01 00 00: 信息对象地址IOA0x0000011号遥测。40 20 00 00: 规一化值NVA0x00002040十进制8256。规一化值需要根据定值系数如K0.001转换为工程值8256 * 0.001 8.256。假设这是电流单位就是kA。02: 品质描述词QDS0x02二进制00000010表示数据有效bit50非取代bit60非封锁bit70未溢出bit80。S帧主站确认接收主站可能不会对每一个I帧都回复I帧那样效率低而是在接收了一批数据后发送一个S帧进行批量确认。主站发送68 04 01 00 0C 00这不是I帧是S帧。S帧的控制域格式固定字节3和4为01 00字节5和6为接收序号N(R)。0C 00即N(R)12小端序。这意味着主站告诉子站“你发送的序号11及之前的所有I帧我都已经收到了。” 子站收到后就可以将发送窗口向前滑动。4.3 遥控选择与执行流程这是一个典型的“选择-返校-执行”两步式遥控确保安全。I帧遥控选择命令C_SC_NA主站发送68 0E 2C 00 0C 00 2D 01 06 00 01 00 0F 00 00 01 00N(S)44 (0x2C), N(R)12。2D: 类型标识0x2D单点遥控命令。06 00: 传送原因0x0006“激活”。01 00: 公共地址1。0F 00 00: IOA0x00000F15号对象假设是某个开关。01: 单点命令SCO。0x01通常表示“合闸”取决于规约具体映射常见的是1合2分。00: 限定词QOS通常为0。I帧遥控选择返校C_SC_NA子站回复68 0E 0A 00 2E 00 2D 01 07 00 01 00 0F 00 00 01 00N(S)10, N(R)46。N(R)46表示子站已收到主站发来的45号及之前的I帧。类型标识2D不变。传送原因变为07 00“激活确认”。其他字段与命令帧一致。这表示子站正确接收了选择命令并已准备好等待执行命令。I帧遥控执行命令C_SC_NA主站发送68 0E 2D 00 0E 00 2D 01 06 00 01 00 0F 00 00 81 00N(S)45, N(R)14。传送原因仍是06 00“激活”。单点命令SCO变为0x81。这里最高位bit8置1通常表示“执行”。所以这个命令的含义是执行15号对象的合闸操作。I帧遥控执行确认C_SC_NA子站回复68 0E 0B 00 30 00 2D 01 07 00 01 00 0F 00 00 81 00传送原因07 00“激活确认”。表示执行命令已接收。随后子站会通过一个**单点遥信变位M_SP_NA**报文将15号开关的状态从“分”更新为“合”传送原因为03 00突发完成整个遥控过程的闭环。5. 工程调试与故障排查实战指南理论再扎实到了现场都可能遇到千奇百怪的问题。下面是我总结的104规约调试“排坑”手册。5.1 调试工具与连接检查工欲善其事必先利其器。必备软件网络调试助手/串口调试助手用于初步测试TCP连接和端口监听。可以模拟客户端或服务端。Wireshark报文分析神器。必须熟练掌握过滤表达式如tcp.port 2404。通过它你可以看到最原始的TCP流和104报文是定位问题的终极手段。规约分析软件厂商提供或第三方如“104规约分析仪”等。这类工具能对抓取的报文进行解析直接显示类型标识、传送原因、IOA等比看十六进制直观得多。连接检查四步法物理链路网线是否插好交换机端口灯是否亮网络可达用笔记本电脑ping子站装置IP通不通端口监听用telnet [子站IP] 2404或nc -zv [子站IP] 2404测试端口是否开放。如果连接被拒绝检查子站程序是否运行、防火墙设置。协议握手用网络调试助手模拟主站发送U帧68 04 07 00 00 00看子站是否回复U帧确认68 04 0B 00 00 00。如果没回复检查子站104服务是否启用、版本是否匹配。5.2 常见故障现象与根因分析下面这个表格整理了最常见的几种问题现象、可能原因和排查思路。故障现象可能原因排查思路与步骤TCP连接无法建立1. 网络不通或IP错误。2. 子站端口2404未监听。3. 防火墙/安全策略拦截。1. Ping测试。2. Telnet测试端口。3. 在子站装置上使用netstat -an或ss -tlnp查看监听端口。4. 检查双方防火墙、ACL策略。连接建立后立即断开或无法启动数据传输1. STARTDTU帧交互失败。2. 双方规约参数如APDU长度、T0/T1/T2/T3超时不匹配。3. 子站收到非法报文如格式错误。1. 用Wireshark抓包确认是否完整交换了STARTDT ACT/CON。2. 核对主站和子站的104规约参数配置表确保一致。3. 检查抓取的第一个I帧格式是否正确。主站能收到部分数据但数据不全或时有时无1. 发送/接收序号V_S/V_R不同步。2. 滑动窗口耗尽。3. 网络存在丢包或延迟抖动。1.重点抓包分析序号对比主站发送的I帧N(S)和子站回复的N(R)以及子站发送的N(S)和主站回复的N(R)看是否连续。2. 检查双方配置的发送/接收窗口大小通常为12最大127。3. 检查网络质量是否存在ARP风暴、广播风暴等。遥控命令下发失败选择超时或无返校1. 控制站地址、公共地址、信息对象地址IOA错误。2. 遥控点号未在子站数据库中定义或定义不一致如分合映射相反。3. 子站当地有“远方/就地”切换把手在“就地”位置。4. 该遥控点被软件置为“封锁”状态。1. 核对主站数据库和子站配置中的遥控点表确保地址、性质完全一致。2. 在子站当地监控后台尝试操作确认就地功能正常。3. 检查子站装置是否有遥控投入压板或软压板未投入。4. 查看子站装置日志或状态字确认遥控点是否被封锁。遥信状态不对与实际相反或抖动1. 通信点表定义不一致如常开/常闭接点定义反了。2. 二次回路问题如接点接触不良、电缆绝缘破损。3. 防抖时间设置过短或过长。1. 核对点表特别是单点/双点类型0x01/0x03和分合状态映射0x01/0x02。2. 在子站装置端子排上测量实际开入量电压与上述状态对比。3. 调整子站装置的遥信去抖时间如从20ms调整为40ms。遥测数据不刷新或数值错误1. 总召唤未成功或未配置周期召唤。2. 变化阈值死区设置过大。3. 系数K设置错误导致工程值换算不对。4. 互感器变比或二次额定值设置错误。1. 确认总召唤流程是否完成传送原因05的报文。2. 检查子站装置的遥测变化上送死区是否设得太大导致无变化不上送。3.核对系数K主站和子站的K值、基值必须完全一致。例如子站发送规一化值NVA10000K0.001则工程值10。主站必须用同样的K值解析。4. 核对CT/PT变比设置。5.3 高级问题与性能优化TCP粘包与拆包104规约基于TCP流而TCP本身没有“报文”概念。极端情况下两条104报文可能被合并成一个TCP包发送粘包也可能一条104报文被拆成多个TCP包拆包。成熟的104规约库必须自己处理粘包拆包依据“68H”启动字符和“长度字节”来正确分割报文。如果使用自行开发的程序这是必须实现的逻辑。时钟同步与带时标传输对于故障分析时标至关重要。104规约支持C_CS_NA时钟同步命令和带CP56Time2a时标的报文如M_SP_TB,M_ME_TF。确保主站定期对子站进行对时并且时区、夏令时设置正确。在分析事故追忆SOE时带时标的突发遥信报文是关键。平衡模式下的流量控制在平衡传输模式下子站可能突发大量变位信息。如果主站处理不过来会导致TCP接收缓冲区满进而影响通信。可以在子站侧配置“最大未确认I帧数”上限或采用“流量控制”ASDU类型标识0x27进行干预。网络中断与重连恢复工业现场网络可能闪断。好的104实现应具备断线重连和断点续传机制。重连后应能自动重新进行总召唤以同步全数据。需要关注主站和子站在连接断开后的清理和初始化逻辑是否完善。搞懂104规约就像是拿到了电力自动化系统内部通信的“密码本”。它没有想象中那么神秘其核心就是一套在TCP/IP之上通过编号、确认、问答机制来保证数据可靠传输的规则。真正的难点不在于协议文本本身而在于如何将纸面的协议与现场千差万别的设备、网络和业务逻辑结合起来。调试的过程就是不断在报文流中寻找线索比对配置定位分歧的过程。我个人的体会是随身带一个便携式交换机在关键链路上做端口镜像抓包是解决一切疑难杂症最直接有效的方法。当你能够熟练地用Wireshark过滤出感兴趣的报文并一眼看出序号在哪里断了链IOA哪里对不上传送原因为何异常时你就真正从104规约的“使用者”变成了“驾驭者”。最后一个小建议建立自己的“报文案例库”把每次遇到的典型问题和对应的报文截图保存下来附上分析过程和解决方案这将成为你未来工作中最宝贵的财富。