ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

IEC104协议如何从源码入门?报文解析与序号机制详解

IEC104协议如何从源码入门?报文解析与序号机制详解 简介IEC 104是电力系统自动化中广泛使用的远动通信协议这份资源是一套以C语言实现的IEC 60870-5-104协议源代码库面向电力自动化开发者、网络通信学习者以及需要解析或构建104报文的工程师。包体为一个RAR压缩包共111个文件大小877KB其中以39个C源码、32个头文件为主并包含makefile编译脚本、TXT说明及证书文件便于在Linux或嵌入式环境下编译使用。已有429人学习浏览。通过研读这套代码可深入理解ASDU与APDU的报文结构、测量值传输与控制命令交互流程、TCP/IP连接管理与超时重传机制以及TLS加密通信的集成方式。代码按CS101、CS104、链路层等模块组织结构清晰适合作为学习IEC 104协议细节和锻炼网络编程能力的实践项目也可为后续开发电力监控或配网自动化设备提供参考。 相信不少刚接触电力自动化通信的同行都经历过这样的阶段手边拿到一份IEC104协议标准文档翻了两页就头大一堆术语堆在一起好不容易看懂了报文结构转头写代码还是不知道怎么下手。我当年学IEC104时也卡在这里真正让我把协议“啃”下来的反而是因为工作需要去读了一套开源的IEC104源代码。没错就是那种标着“仅供自己学习使用”的源码没有商业封装没有炫技写法但恰恰最适合用来搞懂协议本身。那套源码我前前后后读了三遍第一遍通读报文收发链路第二遍追状态机和时序逻辑第三遍自己动手改代码去复现各种边界场景。这篇文章就把我这段源码学习的完整过程复盘一遍包括源码入口怎么找、报文怎么拆、序号和定时器这些容易卡住的难点怎么理解还有怎么验证自己真的读懂了。如果你也在学IEC104愿意静下心啃源码这篇应该能帮你省下不少时间。1. 协议文档那么厚为什么我劝你先从源码下手1.1 看文档容易陷入“每个字都懂连起来不知道在说什么”IEC104标准文档第一遍读下来的真实感受是APCI、ASDU、公共地址、信息体地址、类型标识……这些概念全都有定义但脑子里就是拼不出一个完整画面。文档按信息对象类型、传输规则、状态变迁分成好多章节你需要自己把散落的规则串起来才有意义。源码的区别在于它是把协议规则落成了具体的数据结构和函数调用。你不需要凭空脑补“控制域里的那位是干嘛的”你直接看代码里哪一行在判断它。协议里的每一个抽象概念最终都会落到一个if、一个switch、一个结构体字段上。对我来说这个“从抽象到具体”的转化过程恰恰是读源码最大的价值。1.2 源码是协议规范的“参考实现”不是“唯一答案”有一点先说清楚开源IEC104实现各有各的写法数据结构的组织方式、状态机的实现风格、内存分配策略都可能不一样。所以读源码时要有这个心态——你不是在背一份“标准答案”而是在看别人对协议的一种实现思路。举个例子有的实现把解析报文和处理报文放在同一层有的严格分成协议层和应用层有的用大结构体一把梭有的用小结构体加链式传递。这些差异背后反映的是代码作者对协议职责划分的理解。读的时候重点看作者“为什么这么分”以及“这套分法和标准文档的章节有没有对应关系”。带着这个视角去读收获完全不一样。1.3 光看代码不跑起来等于没看我见过不少同事把源码下载下来人肉读了一遍就觉得自己学会了一动手写代码就露馅。我的建议是源码一定配合通信对端来学。所谓对端可以是另一套开源实现、协议仿真软件甚至是你自己写的测试客户端。两台机器之间真的握手成功了、遥测报文真的显示在界面上了那种“协议通了”的感觉比看十遍代码都管用。原始那句“IEC104源代码仅供自己学习使用”我其实挺认可这个自我定位——别指望一个学习项目能达到工业级稳定性但用学习项目的代码来理解协议原理性价比极高。2. 源码入口怎么找先用十分钟定位三件事2.1 一次connect背后主站和从站的两种视角拿到一套IEC104源码很多人的第一反应是打开main函数从头看。但网络通信程序最忌讳线性阅读因为代码是事件驱动的你不知道下一个报文什么时候来。我更推荐先搞清楚一个最基本的问题这套代码是主站控制端还是从站变电站端主站和从站的核心区别在角色定位主站主动发起连接、发送总召唤、下发遥控指令从站等待连接、被动响应请求、主动上送变化数据。这两类程序虽然都基于IEC104但代码组织有明显差异。你先定位角色再看代码时思路就清晰了主站代码你会更关注“怎么组织一轮总召唤”从站代码你会更关注“收到总召唤后如何遍历所有遥信遥测点”。如果这套源码恰好主站和从站都实现了那更建议先读主站侧。因为主站的逻辑更主动你顺着一次“连接-握手-总召唤-收数据”的完整交互流程去读从站的代码反而好理解了。2.2 I帧、S帧、U帧先认识三种帧类型再去看代码分支IEC104的报文可以分成三类I帧信息帧携带应用数据S帧监视帧只做确认U帧控制帧负责启停和测试。源码里80%的代码都在处理I帧但S帧和U帧决定了连接的稳定性和时序尤其不能漏看。拿到源码后我建议你先在代码里搜三个关键词级别的函数或分支比如send_i_frame、send_s_frame、send_u_frame或者类似命名。把这三个函数找出来读它们的调用关系你会发现U帧通常和连接状态绑定比如STARTDT开始数据传输和STOPDT停止数据传输都是U帧。S帧是由接收事件触发的比如收到一帧后如果暂时没有应用数据要回复就发S帧确认序号避免对端等确认等到超时。I帧是主业务类型标识在这里被分派给不同的处理函数。这套“按帧类型分门别类”的入口梳理做完之后你对代码的全局结构基本就有数了。之后再深入到某个业务细节时不会再迷路。2.3 状态机和序号字段是源码里最值得画图的两个模块IEC104的连接管理是有状态变迁的STOPPED、STARTED两种大状态加上TCP连接是否建立、定时器超时是否触发这些边界情况。源码里一定有一块代码是专门判断当前状态允许做什么操作的读这块代码时要特别留意状态切换的条件。序号字段则是另一个灵魂机制。I帧报文的发送序号和接收序号共同保证传输有序可靠具体的序号跳跃规则和窗口大小约束代码里会有一堆取模运算和比较逻辑。读到这里不要急着跳过去这些都是协议的精髓后面我会专门展开说。3. 报文解析把字节翻译成看得懂的东西3.1 APCI四个字节控制域里藏着的位级运算IEC104报文的最外层结构是APCI应用协议控制信息一共6个字节其中前四个字节对调试最有用控制域里的每一位都有讲究。I帧的控制域是四个字节前两个字节是发送序号后两个字节是接收序号各占12位有效位序号位后面还跟了一个0比特位和帧类型位。S帧的第二个字节是0x01表示S帧后两个字节是接收序号。U帧则用控制域的三个基本位去区分STARTDT、STOPDT、TESTFR。读源码时特别注意这些位运算比如(controlField 1) 0x0FFF这行代码就是从控制域里取出12位的发送序号。自己在心里模拟一遍数值转换比背协议文档里的格式图有效得多。3.2 ASDU字段类型标识、公共地址、信息体地址的协作关系ASDU应用服务数据单元是IEC104里真正承载业务数据的部分。它的公共字段我来重点说三个类型标识一个字节决定了后面信息体的结构和含义。类型标识0x09之类代表遥测0x01代表遥信0x2D代表单点遥控0x64代表总召唤不同的类型标识对应不同的解析分支。公共地址用来区分不同的设备或数据集通常对应变电站里的装置地址。一个主站可能同时管理多个从站公共地址就是区分这些数据源的路由信息。信息体地址用来定位具体的数据点在某个装置里的位置比如“第3路遥测”“第17路遥信”。信息体地址和公共地址组合起来才能唯一确定一个数据点。这三个字段的关系打个比方公共地址是“哪个小区”信息体地址是“哪栋楼哪一户”类型标识是“这个地址上报的信息是温度还是开关状态”。3.3 一个遥测报文的十六进制拆解全过程纸上谈兵没用直接拿一个实际抓包后的十六进制报文来拆。假设收到了这么一串68 14 08 00 00 00 09 03 01 00 01 00 00 00 11 22 33 44按IEC104的结构来拆68启动字符固定为0x68。14APDU长度十六进制0x14等于十进制20表示从下一个字节起到报文末尾一共20个字节。08 00 00 00控制域。第一个字节0x08二进制是0000 1000右移一位是0000 0100对应数值4这个是发送序号第一条I帧的发送序号是2第二条是4所以确实对得上第二个字节0x00是前12位序号的高4位补零第三、四个字节0x00 0x00是接收序号为0。09类型标识根据标准查表可知是带品质描述的归一化遥测值。03信息体数目说明这帧携带了3个信息体。01 00公共地址按低字节在前规则这个报文里是01 00实际值是1。接下来每4个字节是一个信息体信息体地址3个字节加数值1个字节归一化值用1个字节表示百分比。比如01 00 00 11表示信息体地址是1值0x11换算成十进制是17对应17%。依次类推。顺手在源码里找到那个处理类型标识0x09的函数再看一遍它对APDU长度和字段偏移的校验逻辑就能把协议格式和代码验证逻辑对应起来。这一步走完我保证你对ASDU的理解会上一个台阶。4. 序号机制和定时器IEC104最容易踩的两座大山4.1 发送序号和接收序号的“互锁”逻辑IEC104的可靠传输依赖一组序号对发送序号和接收序号各用12位表示范围0~4095。发送方每发一个I帧发送序号加2接收方每正确收到一个I帧接收序号也加2并在回复的S帧或I帧里带上这个接收序号作为确认。源码里这块逻辑很值得细读因为里面有“互锁”的味道。正常情况下发送方只能发送接收序号之前已经确认过的窗口范围内的新帧如果接收序号长时间停留在某个值就说明对端没收到发送方就要考虑重发或者超时处理。“12位序号”这个限制处理不好就是最常见的坑。有些新手直接用了32位整数从头加到尾结果溢出后的行为完全不可控。正确做法是取模运算加差值判断判断(ackNum - sendNum) 0x0FFF是否落在某个阈值内。你会在成熟的源码里看到这类写法。4.2 T0到T3四个超时参数各自盯谁的梢IEC104协议定义了四个关键的超时参数读源码前最好先有个整体印象T0TCP连接建立的超时时间默认30秒。从站对每个连接请求的处理要在T0内给出回应。T1发送或测试帧的确认超时默认15秒。如果发出去的帧在T1内没收到确认连接就被判定异常。T2接收方对无确认数据帧的确认超时。如果没有数据要回就在T2内回一个S帧做确认。比如对于从站来说未及时确认的I帧不能拖过T2。协商的T2一般要小于T1。T3链路空闲时的测试帧周期默认20秒。如果T3时间内双方都没有数据交互就发U帧TESTFR来确认链路还活着。源码里搜T0T1T2T3或者定时器处理回调通常会看到一个用链表或时间轮管理定时器的结构。学习时把这四个超时量的触发条件、重置条件和超时动作列成一张表读到定时器相关代码时对照着看会清晰很多。实际调测中我见过太多次因为T2配置大于T1导致频繁断链的问题了这个知识点不是纸上谈兵。4.3 源码里如何维护连接状态和定时器状态连接状态机和定时器状态往往是联动的。比如从站在STOPPED状态下收到U帧STARTDT act会重置T3定时器把状态切换成STARTED回一个STARTDT con如果此时TCP异常断开定时器回调会把所有待发送数据标记为失败关闭socket然后重新回到等待连接状态。读这块代码时注意作者用了什么数据结构去维护多个连接如果是从站侧通常允许同时接入多个主站以及定时器的“单次/周期”属性是怎么在创建时指定的。理解了状态机加定时器的联动逻辑就等于拿到了IEC104链路的“生命周期管理”钥匙。5. 从“读得懂”到“写得对”用实战验证自己的理解5.1 故意改坏一个字节观察对端的响应读源码读到自己觉得“好像懂了”的时候最忌讳的是自我感动。我推荐一个“破坏性测试”的学习方法把发送报文的某个关键字节改成错误值然后用一套正常的对端程序去接收观察对端的行为。举个我试过的例子把类型标识从0x09改成0x0A带时标的遥测值从站程序就会用另一套逻辑去解析信息体字段长度不对解析立刻报错。又比如把控制域里的发送序号改成5正常应该加2对端会认为序号跳跃触发帧丢弃或重发流程。通过这些破坏性操作你能直观感受到每一段代码存在的意义。5.2 用一个开源客户端和一套仿真工具做联调读源码的同时一定要配一个真实的通信环境做验证。最简单的做法是找几个支持IEC104的客户端和模拟仿真工具比如协议调试助手一头接着标准协议栈一头接你自己读的或者按照源码理解写的程序两边互发报文。我第一次联调时就踩过一个印象深刻的坑我写的主站发送总召唤后迟迟收不到从站的数据抓包发现从站一直在发S帧不响应应用数据。追了半天才发现我的总召唤帧里ASDU的公共地址写的是0而从站配置文件里配的公共地址是1。地址不匹配从站直接把总召唤丢弃了。这类问题在源码里其实都有校验逻辑但你不实际联调一遍很难真正意识到地址匹配的重要性。5.3 把握手、总召、遥测、遥控四条链路串起来读一遍源码读到后期我建议把四条核心链路依次串读一遍TCP连接建立后的握手U帧STARTDT交互、总召唤类型标识0x64、遥测上送类型标识0x09/0x0A等、遥控下发类型标识0x2D/0x2E等。每一条链路都从发送方构造报文开始到接收方解析处理结束中途涉及到的序号更新、定时器管理、状态判断全部在这一遍串读中过一遍。四遍串读走下来你对这套IEC104源码的理解就不再是零散的“某个函数干什么”而是完整的“一个事件如何穿过整个协议栈”。这时候哪怕你关掉源码自己从零写也能轻松搭出正确的主流程框架。我把这个“串读四链路”的方法推荐给了几个带过的新人坚持照做的基本都在一周左右完成了从“读不懂”到“能独立改功能”的跨越。这个阶段的成就感确实是翻阅十遍协议文档都换不来的。6. 关于“仅供自己学习使用”的一点个人看法很多人看到项目里写着“仅供自己学习使用”就不太当回事觉得复杂度有限、代码风格可能也比较随意。但从学习角度这类项目有一个同类商业实现没有的优势——它没有过度封装协议处理的骨架是露在外面能直接看到的。我之前也读过一些商业封装后的协议栈学习体验反而不如这种“素颜”源码。商业协议栈为了适配多平台、多语言场景往往加了很多抽象层和宏开关你翻完整套代码连“I帧在哪构造”都要找半天。学习用源码通常直来直去一个线程收报文一个线程发报文收到什么类型就调用什么函数学习成本低得多。当然如果你想在生产项目里用这套代码那还是得谨慎评估它的边界处理、异常恢复能力以及是否有安全加固。我的态度一直是源码项目的价值在于“教会你原理”这也是“仅供学习使用”这句话的真实含义——它负责让你学会不负责替你上生产。本文还有配套的精品资源点击获取
返回列表