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

每一层都有固定的字节偏移和含义,抓包时按这个结构去拆,基本不会出错。

TPKT 4字节 | 传输层 ISO-COTP 3~7字节 | 会话层 S7 Header 10字节 | 协议头 S7 Parameter 可变长度 | 请求/响应参数 S7 Data 可变长度 | 实际数据 外层封装 连接管理 协议控制 参数+数据(核心载荷) S7协议报文五层结构示意图 每一层都有固定偏移和含义,抓包时按此结构逐层解析

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