3. S7协议报文结构:TPKT、ISO-COTP、S7 Header、S7 Parameter、S7 Data
好,咱们今天来聊聊S7协议报文到底长什么样。说实话,我刚接触S7协议那会儿,看着抓包软件里那一串十六进制数,脑袋都是懵的。后来跟着老工程师一点点拆解,才发现这东西其实挺有规律。
S7通信的报文,说白了就是一层套一层的结构。就像寄快递——先有个外包装(TPKT),里面有个信封(ISO-COTP),信封里装着信纸(S7协议部分)。而S7协议部分又分三块:头部、参数、数据。我习惯把这五层叫做「五件套」,少了哪一层都不行。
核心记忆点:S7报文 = TPKT + ISO-COTP + S7 Header + S7 Parameter + S7 Data
每一层都有固定的字节偏移和含义,抓包时按这个结构去拆,基本不会出错。
3.1 TPKT——最外层的快递盒
TPKT是ISO 8073定义的传输层协议,说白了就是个「信封皮」。它只有4个字节,结构简单到令人发指:
| 字节偏移 | 长度 | 含义 | 典型值 |
|---|---|---|---|
| 0 | 1 | 版本号 | 0x03 |
| 1 | 1 | 保留位 | 0x00 |
| 2-3 | 2 | 整包长度(含TPKT自身) | 例如0x0025(37字节) |
我记得第一次抓包时,看到TPKT版本号永远是0x03,还以为是固定死的。后来查资料才知道,ISO 8073就定义了这一个版本,所以不用纠结。
实战技巧:解析报文时,先读TPKT的第2-3字节,就能知道整个报文有多长。我习惯用这个值来校验报文是否完整——如果实际收到的字节数小于这个值,说明数据包被截断了,直接丢弃。
3.2 ISO-COTP——连接管理的信使
ISO-COTP(Connection-Oriented Transport Protocol)负责管理连接。它有两种常见类型:
- CR(Connection Request,0x0E):建立连接请求
- CC(Connection Confirm,0x0D):连接确认响应
- DT(Data Transfer,0x0F):数据传输
嗯,这里要注意:在S7通信中,建立连接时用CR/CC,正常读写数据时用DT。我见过不少新手把DT报文当成CR来解析,结果死活对不上。
ISO-COTP的结构大致如下:
字节0: 长度(包含自身)
字节1: 类型(0x0E/0x0D/0x0F)
字节2: 目的引用
字节3: 源引用
字节4+: 可选参数(如TSAP)
说白了,ISO-COTP就是告诉对方「我要跟你说话」或者「我同意跟你说话」。一旦连接建立,后续报文就全是DT类型了。
3.3 S7 Header——协议的控制中心
S7 Header是10个字节的固定头部,它决定了这次通信是读还是写、是请求还是响应。结构如下:
| 字节偏移 | 长度 | 含义 | 说明 |
|---|---|---|---|
| 0 | 1 | 协议ID | 固定0x32 |
| 1 | 1 | 消息类型 | 0x01=请求, 0x02=响应, 0x03=ACK, 0x07=用户数据 |
| 2-3 | 2 | 保留/冗余 | 通常为0x0000 |
| 4-5 | 2 | 协议数据单元引用 | 请求与响应对应的标识 |
| 6-7 | 2 | 参数总长度 | 不含Header自身 |
| 8-9 | 2 | 数据总长度 | 不含Header和参数 |
我个人习惯把S7 Header叫做「指挥中心」——它告诉你后面跟着什么参数、什么数据,以及这次通信是干嘛的。比如消息类型0x01表示这是PLC发来的请求,0x02表示上位机返回的响应。
避坑指南:我曾经在解析响应报文时,直接拿请求报文的参数长度去读响应,结果数据全乱了。后来才意识到——请求和响应的参数长度可能不一样!一定要以当前报文的S7 Header中声明的长度为准。
3.4 S7 Parameter——具体操作的指令
S7 Parameter是可变长度的,它描述了具体要做什么操作。常见的参数类型有:
- 0x04:读取数据(Read)
- 0x05:写入数据(Write)
- 0x1A:请求数据块信息
- 0x1C:时间同步
以读取DB块为例,参数结构大致是:
字节0: 功能码(0x04)
字节1: 项目数(通常为1)
字节2-3: 数据块类型(0x0001=DB, 0x0002=MB, 0x0003=PI等)
字节4-5: 数据块编号(如DB1就是0x0001)
字节6: 访问类型(0x82=字节访问)
字节7-8: 起始地址
字节9-10: 读取长度(位为单位)
你想想看,这个参数其实就是告诉PLC:「我要读DB1的第0个字节,读2个字节」。PLC收到后就知道该从哪里取数据了。
3.5 S7 Data——真正的数据载荷
S7 Data是报文的最后一部分,存放实际的数据内容。对于读取请求,Data段可能为空;对于读取响应,Data段就是PLC返回的数据。对于写入请求,Data段就是你要写入的值。
数据格式取决于访问类型:
- 字节访问:直接返回字节值
- 字访问:返回2字节,高字节在前
- 双字访问:返回4字节,大端序
我记得有一次调试时,上位机读到的数据总是反的。查了半天,发现是字节序搞错了——S7协议用的是大端序(高字节在前),而我的解析代码默认用了小端序。改过来就对了。
总结一下:
TPKT告诉你「包裹有多大」
ISO-COTP告诉你「连接状态」
S7 Header告诉你「操作类型和长度」
S7 Parameter告诉你「具体操作什么」
S7 Data告诉你「实际数据是什么」
五层结构,层层递进,缺一不可。
好了,S7协议的报文结构就这些。你只要记住这五层,抓包时按顺序拆解,基本不会出大问题。下次咱们聊聊怎么用代码实现报文的拼装和解析——那才是真正动手的时候。
公众号:蓝海资料掘金营,微信deep3321