物联网-S7Comm协议
■ 调试工具 ■ S7协议-简介 ■ S7协议和modbusTCP协议区别 ■ OSI 层 S7 协议 ■ S7协议数据结构 (TPKT+COTP+S7Comm) ■ TPKT(第五层:会话层) 总共占4个字节 ■ COTP(第六层:表示层) ■ 1. COTP连接包(COTP Connection Packet)也就是S7Comm的握手包 ■ 2. COTP功能包 (COTP Fuction Packet)
■ S7Comm(第七层:应用层)总用占24个字节 ■ 1. S7Comm Header: ■ 2. S7Comm Parameter:
■ S7协议的工作流程 ■ 数据包分析 ■ S7 Setup Communication (Job) ■ S7 Setup Communication (ACk_data) ■ 读取数据 (Job) ■ 读取数据 (ACk_data) ■ 读取数据
■ 读写部分代码
■ 调试工具
Wireshark 抓包工具 Wireshark 抓包工具进行抓包看详细的发送报文格式。 西门子PLC调试助手
■ S7协议-简介
S7Comm( S7 Communication)是西门子专有的协议,是西门子 S7 通讯协议簇里的一种。 S7 通信协议是西门子 S7 系列 PLC 内部集成的一种通信协议,是 S7 系列 PLC 的精髓所在。 它是一种运行在传输层之上的(会话层/表示层/应用层)、经过特殊优化的通信协议,其信息传输可以基于 MPI 网络、 PROFIBUS 网络 或者以太网。
■ S7协议和modbusTCP协议区别
项目 说明 1 工作方式:S7协议是基于串行通信方式进行通信的, 而modbusTCP协议则采用了基于以太网的通信方式,可以实现更高的数据传输速度和数据量。 2 通信速度:S7通信速度相对较慢,一般为12Mbps以下; modbusTCP协议则支持更高的通信速度和更广的数据带宽,可达到100Mbps或以上的速度。 3 网络拓扑:S7协议在网络拓扑方面相对简单,通常采用星形网络拓扑; 而modbusTCP协议支持基于以太网的网状拓扑结构,可以实现更复杂的网络配置和更完备的自组网功能。 4 实时性:modbusTCP协议具有更高的实时性能,可满足工业自动化领域的实时控制要求。
■ OSI 层 S7 协议
OSI层 S7 协议 – 第 7 层: 应用层 S7 协议 S7 Communication 第 6 层: 表示层 S7 协议(COTP) 第 5 层: 会话层 S7 协议(TPKT) 第 4 层: 传输层 Transmission Control Protocol 第 3 层: 网络层 IP 第 2 层: 数据链路层 Ethernet 第 1 层: 物理层 Ethernet
■ S7协议数据结构 (TPKT+COTP+S7Comm)
■ TPKT(第五层:会话层) 总共占4个字节
版本号 预留 长度 1字节 1字节 2字节 0x03 0x00 0x001F
■ COTP(第六层:表示层)
■ 1. COTP连接包(COTP Connection Packet)也就是S7Comm的握手包
长度 PDU类型(DT Data) 目标引用 DST Ref SRC Ref Opt Parameters 1字节 1字节 2 字节 2 字节 1字节 N 字节
■ 2. COTP功能包 (COTP Fuction Packet)
Length PDU type opt 1字节 1字节 1字节 注意:长度不包含length的长度 PDU类型 Boolean类型
PDU类型 介绍 0x1: ED Expedited Data,加急数据 0x2: EA Expedited Data Acknowledgement,加急数据确认 0x4: UD,用户数据 0x5: RJ Reject,拒绝 0x6: AK Data Acknowledgement,数据确认 0x7: ER TPDU Error,TPDU错误 0x8: DR Disconnect Request,断开请求 0xC: DC Disconnect Confirm,断开确认 0xD: CC Connect Confirm,连接确认 0xE: CR Connect Request,连接请求 0xF: DT Data,数据传输
■ S7Comm(第七层:应用层)总用占24个字节
■ 1. S7Comm Header:
协议ID(Protocol ID) PDU type 预留 PDU Reference 参数长度 数据长度 Error class Error code 1字节 1字节 2字节 2字节 2字节 2字节 1字节 1字节
编号 类型字节 说明 0 (unsigned integer, 1 byte): Protocol Id,协议ID,通常为0x32; 1 (unsigned integer, 1 byte): ROSCTR,PDU type,PDU的类型 2~3 (unsigned integer, 2 bytes): Redundancy Identification (Reserved),冗余数据,通常为0x0000; 4~5 (unsigned integer, 2 bytes): Protocol Data Unit Reference,it’s increased by request event。协议数据单元参考,通过请求事件增加; 6~7 (unsigned integer, 2 bytes): Parameter length,the total length (bytes) of parameter part。参数的总长度; 8~9 (unsigned integer, 2 bytes): Data length,数据长度。如果读取PLC内部数据,此处为0x0000;对于其他功能,则为Data部分的数据长度; 10 (unsigned integer, 1 bytes): Error class,错误类型: 11 (unsigned integer, 1 bytes): Error code,错误代码;
■ 2. S7Comm Parameter:
功能码 Read Var:0x04
通信项数:0x01
(Item1)通信项1 :
通信项 Header
变量指定: 0x12
地址长度: 0x0A
SyntaxID: 0x10
传输数据类型byte: 0x02
通信项 Param
读取长度: 0x04
DB号: 0x01
存储区类型DB存储区: 0x84
开始字节: 0x000000
编号 类型字节 说明 0 (Unsigned integer, 1 byte): Variable specification,确定项目结构的主要类型,通常为0x12,代表变量规范; 1 (Unsigned integer, 1 byte): Length of following address specification,本Item其余部分的长度; 2 (Unsigned integer, 1 byte): Syntax Ids of variable specification,确定寻址模式和其余项目结构的格式; 3 (Unsigned integer, 1 byte): Transport sizes in item data,确定变量的类型和长度: 4~5 (Unsigned integer ,2 byte): Request data length,请求的数据长度; 6~7 (Unsigned integer, 2 byte): DB number,DB模块的编号,如果访问的不是DB区域,此处为0x0000; 8 (Unsigned integer, 1 byte): Area,区域类型: 9~11 (Unsigned integer, 3 byte): Address,地址。
■ S7协议的工作流程
工作流程 说明 1 client与server 通过socket和标准的TCP的方式建立连接 2 client发送COTP,请求连接PLC,报文中包含Source TSAP和Destination TSAP,从而标识出CPU的机架号和槽号 3 PLC返回COTP,确认连接,报文中包含Source TSAP和Destination TSAP,此时server确定client与哪个CPU进行通讯 4 client发送S7 Communication给server,报文中包含Setup communication,即通讯请求,包含PDU的长度 5 server返回S7 Communication给client,报文的ROSCTR为ACK_DATA,有确认的意思,包含PDU的长度 6 client与server发送交换数据的报文,仍以S7 Communication完成
2与3完成数据传输前连接的功能, 4与5则完成连接之后的通讯请求,如果绕过通讯请求的建立,在有TCP时就进行数据交换,服务器一般会直接断连。
建立Socket连接:进行TCP三次握手 COTP的握手请求(请求建立通信) 整个S7的握手请求(请求建立操作通信) 进行读写操作(S7协议报文)
■ 数据包分析
■ S7 Setup Communication (Job)
■ S7 Setup Communication (ACk_data)
■ 读取数据 (Job)
■ 读取数据 (ACk_data)
0x123 == data 0x007b
■ 读取数据
■ 读写部分代码
using System;
using System. Net. Sockets;
namespace Zhaoxi. SiemensS7. Study
{
class Program
{
static void Main ( string[ ] args)
{
Console. WriteLine ( "Hello World!" ) ;
S7. Net. Plc plc = new S7. Net. Plc ( S7. Net. CpuType. S71500, "192.168.151.200" , 0 , 1 ) ;
plc. Open ( ) ;
Socket socket = new Socket ( AddressFamily. InterNetwork, SocketType. Stream, ProtocolType. Tcp) ;
socket. Connect ( "192.168.151.200" , 102 ) ;
try
{
byte[ ] cotpBytes = new byte[ ] {
0x03 , 0x00 , 0x00 , 0x16 ,
0x11 ,
0xe0 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0xc1 , 0x02 , 0x10 , 0x00 ,
0xc2 , 0x02 , 0x03 , 0xFF ,
0xc0 , 0x01 , 0x0a
} ;
socket. Send ( cotpBytes) ;
int count = socket. Receive ( new byte[ 22 ] ) ;
}
catch ( Exception ex)
{
}
byte[ ] setupBytes = new byte[ ] {
0x03 , 0x00 , 0x00 , 0x19 ,
0x02 ,
0xf0 ,
0x80 ,
0x32 ,
0x01 ,
0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x08 ,
0x00 , 0x00 ,
0xf0 ,
0x00 ,
0x00 , 0x03 ,
0x00 , 0x03 ,
0x03 , 0xc0
} ;
socket. Send ( setupBytes) ;
int byteAddr = 10 ;
int bitAddr = 0 ;
byteAddr = byteAddr << 3 ;
byteAddr += bitAddr;
byte[ ] readBytes = new byte[ ] {
0x03 , 0x00 , 0x00 , 0x2b ,
0x02 ,
0xf0 ,
0x80 ,
0x32 ,
0x01 ,
0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x1a ,
0x00 , 0x00 ,
0x04 ,
0x02 ,
0x12 , 0x0a ,
0x10 ,
0x04 ,
0x00 , 0x01 ,
0x00 , 0x02 ,
0x84 ,
( byte) ( byteAddr/ 256 / 256 % 256 ) ,
( byte) ( byteAddr/ 256 % 256 ) ,
( byte) ( byteAddr% 256 ) ,
0x12 , 0x0a ,
0x10 ,
0x01 ,
0x00 , 0x02 ,
0x00 , 0x00 ,
0x81 ,
( byte) ( ( ( 2 << 3 ) + 1 ) / 256 / 256 % 256 ) ,
( byte) ( ( ( 2 << 3 ) + 1 ) / 256 % 256 ) ,
( byte) ( ( ( 2 << 3 ) + 1 ) % 256 )
} ;
socket. Send ( readBytes) ;
}
}
}