2. DNP3协议栈结构:物理层、数据链路层、传输层、应用层详解
好,咱们直接切入正题。DNP3这个协议,说白了就是一套“规规矩矩”的通信语言。它不像Modbus那么“野”,上来就干。DNP3是分层设计的,每一层各司其职。我经常跟学员讲,你把它想象成一个快递公司,从寄件到收件,每个环节都有专人负责。
DNP3协议栈一共四层:物理层、数据链路层、传输层、应用层。嗯,这里要注意,它没有网络层。为什么?因为DNP3最初设计就是跑在串口上的,串口不需要路由。后来扩展到了TCP/IP,但那是把整个DNP3报文当成了TCP的负载,这是后话了。
2.1 物理层:最底层的“电线”
物理层,说白了就是信号怎么在线上跑。DNP3对物理层没有强制规定,但实际项目中,我见过最多的就是RS-232和RS-485。
- RS-232:点对点,距离短(15米左右)。老式RTU常用。我个人习惯,调试时首选RS-232,简单直接。
- RS-485:多点通信,距离远(1200米)。变电站里几乎全是它。我记得有一次在西北的风电场,光纤还没铺好,全靠RS-485手拉手把几十台风机串起来,跑了两年都没出过大问题。
- TCP/IP:现在的新站,基本都是以太网了。DNP3 over TCP,端口号20000。你想想看,一个站控层交换机,下面挂几十台IED,全走网络,维护起来多方便。
2.2 数据链路层:帧的“搬运工”
数据链路层,是DNP3最核心的一层。它负责把原始比特流组装成“帧”。一个DNP3帧长什么样?我直接给你看结构:
| 起始字 (0x0564) | 长度 | 控制字 | 目的地址 | 源地址 | CRC | 用户数据 | CRC | ... | CRC |
这里有几个关键点,我一个个说:
- 起始字:固定0x0564。接收端看到这个,就知道“哦,DNP3报文来了”。
- 长度:从控制字开始到最后一个CRC的字节数。注意,不包含起始字和长度本身。
- 控制字:这是灵魂。它决定了这个帧是主站发的还是从站发的,是请求还是响应,要不要确认。
- 地址:DNP3的地址范围是0到65535。我建议你给每个设备分配一个唯一的地址,别偷懒用默认值。我曾经见过一个站,两台保护装置都设成了地址1,结果一召唤数据,两台同时响应,报文全乱了。
- CRC:每16个字节就有一个CRC校验。DNP3对数据完整性要求极高,这一点比Modbus强太多。
2.3 传输层:大数据的“拆分器”
你想想看,数据链路层一帧最多能传多少数据?答案是250字节左右(包含开销)。但有时候,一个应用层报文可能很大,比如历史事件记录,可能有几千字节。怎么办?
这时候传输层就上场了。它的工作很简单:把大的应用层报文拆成多个小段,每个小段塞进一个数据链路层帧里。接收端再把这些小段拼回去。
传输层的头部只有两个字节:
| 位7-6: 保留 | 位5: FIN | 位4: FIR | 位3-0: 序号 |
- FIR:第一个分片。为1时,表示这是整个报文的第一段。
- FIN:最后一个分片。为1时,表示这是整个报文的最后一段。
- 序号:从0到15循环。接收端靠这个来排序和检测丢包。
举个例子:一个应用层报文被拆成了3段。第一段的FIR=1,FIN=0,序号=0;第二段的FIR=0,FIN=0,序号=1;第三段的FIR=0,FIN=1,序号=2。接收端收到后,按序号拼起来,就是一个完整的报文。
2.4 应用层:真正的“业务逻辑”
应用层,才是我们真正关心的。它定义了“读什么数据”、“写什么数据”、“怎么控制”。
应用层报文的结构是这样的:
| 应用层头部 | 对象头 | 数据 |
应用层头部包含:
- 应用层控制字:包含FIR、FIN、CON(是否需要确认)、序列号等。
- 功能码:这是核心。比如0x01是“读”,0x02是“写”,0x05是“直接操作”,0x14是“响应”。
- 内部指示字(IIN):从站返回的状态信息。比如“设备重启了”、“缓冲区满了”、“时间不同步”等。
对象头则定义了数据的“类型”和“格式”。DNP3把数据分成了很多“对象组”和“对象变体”。比如:
| 对象组 | 对象变体 | 描述 |
|---|---|---|
| 01 | 01 | 二进制输入(单点) |
| 01 | 02 | 二进制输入(带状态) |
| 10 | 01 | 二进制输出(控制继电器) |
| 30 | 01 | 模拟输入(32位浮点) |
| 40 | 01 | 模拟输出(16位整数) |
你想想看,有了这个对象模型,主站和从站之间就能精确地知道“我要读第1组第1变体的数据”,而不是像Modbus那样只知道“读寄存器地址100”。这就是DNP3灵活的地方。
2.5 四层之间的协作
最后,我画个简单的流程,帮你理解这四层是怎么配合的:
- 应用层:主站想读从站的遥测数据。它构造一个“读请求”报文,功能码=0x01,对象=30变体01。
- 传输层:如果这个请求报文太大,传输层把它拆成多个分片,每个分片加上FIR/FIN和序号。
- 数据链路层:每个分片被封装成一个帧,加上起始字、地址、CRC。然后交给物理层。
- 物理层:把帧变成电信号(RS-485差分电平)或者光信号(光纤),发到线路上。
从站收到后,反过来:物理层收信号,数据链路层校验CRC、检查地址,传输层拼分片,应用层解析请求并执行。
嗯,这就是DNP3协议栈的全貌。每一层各干各的,互不干扰。这种分层设计的好处是,你换物理层(比如从串口换成以太网),上三层完全不用改。我在项目中就干过这事,把老站点的RS-485升级成光纤环网,只改了物理层配置,应用层代码一行没动。
下一章,我会带你手把手配置一个DNP3从站,把今天讲的这些层,一个一个在软件里实现出来。