手摸手教你撕碎西门子S7通讯协议04--S7COMM请求

news2024/11/13 8:02:59

1、S7通讯回顾

    - (1)建立TCP连接      Socket.Connect-》已实现

     - (2)发送访问请求     COTP-》已实现 

     - (3)交换通信信息     Setup Communication-》本节实现

     - (4)执行相关操作     读、写、PLC启停、时间、上传下载-》待实现


 2、S7COMM请求介绍

在成功完成上面的socket连接和COTP请求后,现在客户端还不能进行读写操作,还需要进行请求建立通信,所以客户端需要发送S7 Communicaton报文给服务端,在S7Communicaton报文中包含“通讯请求”; 服务端反馈S7 Communicaton报文。同样的报文中每个字段都有含义,必须严格遵守,这个过程是交换通信信息, 报文信息如下

 注意下面几点:

1》从中可以看到发送是25个字节,响应是27个字节,可以看到发送报文由4个部分构成:TPKT占4个字节0-3,COTP占3个字节4-6,S7-Header占10个字节7-16,S7-Parameter占8个字节17-24,看到了不?但是响应报文27个,也是由4个部分构成,但S7-Header占12个字节,其他一样长度,注意了不?仔细看这里,明白了,一定要搞明白哦。

 2》ROSCTR,它是个枚举值,具体如下:

看这个地方的不同,发送是01,响应是03,对应上面的值就是表示上位机请求是job,PLC响应是从站响应并带数据 

3》PDU Type,跟上节的不一样,这次是发送接收都是f0,上节的COTP报文是e0和d0,再来看下

4》Error class已知枚举值,这个出现在响应报文中,可以看到00表示没有错误,这是我们必须看到的,如果不是00表示你的报文有bug

 5》Error code已知枚举值,这个出现在响应报文中,可以看到00表示没有错误,这是我们必须看到的,如果不是00表示你的报文有bug

6》发送报文中的功能码,即17字节,Function已知枚举值,现在知道发送报文为什么是f0了吧

这些东西都要明白,否则写起代码起来就会出错,就不能象我一样进行如此的剖析和手撕,来个超级的啵啵啵。

3、开搞S7COMM通信  

 完整代码 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace west.siemenscomm
{
    internal class Program
    {
        /// <summary>
        /// plc的ip地址
        /// </summary>
        static string _ip = "192.168.1.66";
        /// <summary>
        /// 端口号
        /// </summary>
        static int _port = 102;
        /// <summary>
        /// 机柜号,插槽号
        /// </summary>
        static byte _rack = 0, _slot = 1;
        /// <summary>
        /// socket对象
        /// </summary>
        static Socket socket = null;
        /// <summary>
        /// 时间事件
        /// </summary>
        static ManualResetEvent TimeoutObject = new ManualResetEvent(false);
        /// <summary>
        /// 连接状态 
        /// </summary>
        static bool connectState = false;
        /// <summary>
        /// 通讯连接的pdu长度
        /// </summary>
        static short _pduSize = 240;

        static void Main(string[] args)
        {
            Connect();
            if (connectState)
            {
                COTPConnection();
                if (connectState)
                {
                    SetupCommunication();
                }
            }

            Console.ReadKey();
        }

        /// <summary>
        /// 通讯连接
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        private static bool SetupCommunication()
        {
            //s7comm连接包括4个部分,共25个字节,即25=4+3+10+8 
            byte[] setupBytes = new byte[] {
                // 1)TPKT包括4个字节
                0x03,//版本默认3
                0x00,//保留默认0
                0x00,//整个请求字节数高位
                0x19,//整个请求字节数低位,0x19转换成10进制就是25
               //2)COTP包括3个字节
                0x02,//当前字节以后的字节数(不包括自已,0x02转换成10进制就是2),注意这个“当前字节以后的字节数”是指COTP这部分,而不是整个字节部分
                0xf0,//PDU Type,0xe0 连接请求,0xd0 连接确认,0x08 断开请求,0x0c 断开确认,0x05 拒绝访问,0x01 加急数据,0x02 加急数据确认,0x04 用户数据,0x07 TPDU错误,0xf0 数据传输
                0x80,//TPDU number,固定值
                // 3)Header包括10个字节
                0x32,//默认值,协议id
                0x01,//ROSCTR,0x01 Job request。主站发送请求,0x02 Ack。从站响应请求不带数据,0x03 Ack_Data。从站响应请求并带有数据,0x07 Userdata。原始协议的扩展。读取编程/调试、SZL读取、安全功能、时间设置等
                0x00,//Redundancy Identification (Reserved)固定值,占2个字节
                0x00,
                0x00,//Protocol Data Unit Reference固定值,占2个字节
                0x00,
                0x00,//Parameter length参数长度,占2个字节
                0x08,
                0x00,//Data length数据长度,占2个字节
                0x00,
                // 4)Parameter包括8个字节
                0xf0,//Function功能码,具体是:0x00 CPU服务,0xF0 设置通信,0x04 读取变量,0x05 写变量,0x1A 请求下载,0x1B 下载块,0x1C 下载结束,0x1D 开始上传,0x1E 上传,0x1F 结束上传,0x28 PLC 控制,0x29 PLC 停止
                0x00,//保留默认值
                0x00,//Max AmQ(parallel jobs with ack) calling,占2个字节
                0x03,
                0x00,//Max AmQ(parallel jobs with ack) called,占2个字节
                0x03,
                0x03,//PDU length,占2个字节,0x03co转换成10进制就是960
                0xc0
            };
            try
            {
                socket.Send(setupBytes);
                //响应报文的长度就是固定的27个字节
                byte[] respBytes = new byte[27];
                int count = socket.Receive(respBytes);
                // 拿到PDU长度   后续进行报文组装和接收的时候可以参考
                byte[] pdu_size = new byte[2];
                pdu_size[0] = respBytes[26];
                pdu_size[1] = respBytes[25];
                _pduSize = BitConverter.ToInt16(pdu_size,0);
                if (respBytes[17] != 0x00&& respBytes[18] != 0x00)
                {
                    Console.WriteLine("粗问题,COMM连接响应异常");
                    connectState = false;
                }
                else
                {
                    Console.WriteLine("太好了,COMM连接响应正常");
                    connectState = true;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Setup通信未建立!" + ex.Message);
                connectState = false;
            }
            return connectState;
        }

        /// <summary>
        /// cotp连接
        /// </summary>
        private static bool COTPConnection()
        {
            //COTP连接包括2个部分,共22个字节),22=4+18
            byte[] cotpBytes = new byte[] {
                //1)TPKT包括4个字节
                0x03,//版本号,版本默认3
                0x00,//默认保留为0
                0x00,//整个请求字节高位
                0x16,//整个请求字节低位(0x16转换成为10进制就是22)
                //2)COTP包括18个字节 
                0x11,//当前字节以后的字节数(不包括自已,0x11转换成10进制就是17)
                0xe0,//PDU type,0xe0 连接请求,0xd0 连接确认,0x08 断开请求,0x0c 断开确认,0x05 拒绝访问,0x01 加急数据,0x02 加急数据确认,0x04 用户数据,0x07 TPDU错误,0xf0 数据传输
                0x00,//DST reference(2个字节)
                0x00,//
                0x00,//SRC reference(2个字节)
                0x00,//
                0x00,//class(固定的) 
                0xc1, //Parameter-code  src-tsap 上位机
                0x02,  //Parameter-Len   
                0x10 ,   //Source TSAP:01->PG;02->OP;03->S7单边(服务器模式);0x10->S7双边通 
                0x00,   //机架与插槽号为0   
                0xc2,//Parameter-code  dst-tsap PLC 
                0x02,//Parameter len  
                0x03,//Destination TSAP  
                (byte)(_rack*32+_slot),//机架与插槽号: 
                0xc0,  //    Parameter code:tpdu-size 
                0x01,   //   Parameter length
                0x0a  //    TPDU size 
            };
            try
            {
                socket.Send(cotpBytes);
                //响应报文的长度是固定的22个字节
                byte[] respBytes = new byte[22];
                int count = socket.Receive(respBytes, 0, 22, SocketFlags.None);
                //第5个字节是pdu type,具体是:0xe0 连接请求,0xd0 连接确认,0x08 断开请求,0x0c 断开确认,0x05 拒绝访问,0x01 加急数据,0x02 加急数据确认,0x04 用户数据,0x07 TPDU错误,0xf0 数据传输
                if (respBytes[5] != 0xd0)
                {
                    Console.WriteLine("粗问题,COTP连接响应异常");
                    connectState = false;
                }
                else
                {
                    Console.WriteLine("太好了,COTP连接响应正常");
                    connectState = true;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("COTP连接未建立!" + ex.Message);
                connectState = false;
            }
            return connectState;
        }
        /// <summary>
        /// tcp连接 
        /// </summary>
        /// <param name="timeout"></param>
        private static void Connect(int timeout = 50)
        {
            TimeoutObject.Reset();
            try
            {
                socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                socket.BeginConnect(_ip, _port, callback =>
                {
                    connectState = false;
                    var cbSocket = callback.AsyncState as Socket;
                    if (cbSocket != null)
                    {
                        connectState = cbSocket.Connected;
                        if (cbSocket.Connected)
                            cbSocket.EndConnect(callback);
                    }
                    TimeoutObject.Set();
                }, socket);
                TimeoutObject.WaitOne(2000, false);
            }
            catch (SocketException ex)
            {
                if (ex.ErrorCode == 10060)
                    Console.WriteLine(ex.Message);
            }
            if (socket == null || !socket.Connected || ((socket.Poll(200, SelectMode.SelectRead) && (socket.Available == 0))))
            {
                Console.WriteLine("网络连接失败");
            }
            Console.WriteLine(connectState == true ? "连接成功" : "连接失败");
        }
    }
}

4、运行测试

5、小结

这就是第3个流程,建立comm连接,它是通过socket对象通讯实现的,小伙伴们,明白了不?下节继续屌起来。

原创不易,打字截图不易,走过路过,不要错过,欢迎点赞,收藏,转载,复制,抄袭,留言,动动你的金手指,早日实现财务自由

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1957507.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

诱骗IoT恶意软件跟踪CC服务器

工作背景 在分析 IoT 僵尸网络时&#xff0c;识别C&C 服务器至关重要。C&C 服务器的 IP 地址一直都是商业威胁情报的重要组成部分&#xff0c;由于 C&C 服务器通信协议日渐复杂并且活跃周期较短&#xff0c;时效性和准确性也非常重要。如果可以自动化识别 IoT 恶意…

深度学习实战笔记3循环神经网络实现

我们要训练一个基于循环神经网络的字符级语言模型&#xff0c;根据用户提供的文本的前缀生成后续文本。 import math import torch from torch import nn from torch.nn import functional as F from d2l import torch as d2l batch_size, num_steps 32, 35 train_iter, voc…

防震减灾知识竞赛的规则和流程方案

防震减灾知识竞赛的规则主要包括赛制、比赛形式、参赛对象、竞赛内容等方面。 赛制&#xff1a;通常包括选拔赛、分区预赛和全国决赛三个阶段。选拔赛可以根据地区实际情况选择合适的组织形式&#xff0c;预赛和决赛则以现场比赛形式进行&#xff0c;由主办单位统一组织。 比…

掌握 Spring Boot + MyBatis-Plus 动态数据源切换,只要5分钟!

数据量猛增&#xff0c;通过动态数据源切换&#xff0c;我们不仅能提高查询效率&#xff0c;还能保证系统的高可用性。 通过将写操作集中在主库&#xff0c;读操作分散到多个从库&#xff0c;可以有效减轻数据库的压力。 在pom.xml中添加以下依赖&#xff1a; xml <depend…

记录|LabVIEW从0开始

目录 前言一、表达式节点和公式节点二、脚本与公式2.1 公式 三、Excel表格3.1 位置3.2 案例&#xff1a;波形值存入Excel表中3.3 案例&#xff1a;行写入&#xff0c;列写入 四、时间格式化4.1 获取当前时间4.2 对当前时间进行格式化 更新时间 前言 参考视频&#xff1a; LabVI…

hadoop学习(二)

一.MapReduce 1.1定义&#xff1a;是一个分布式运算程序的编程框架 1.2核心功能&#xff1a;将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序&#xff0c;并发运行在一个Hadoop集群上。 1.3优点 1&#xff09;易于编程 它简单的实现一些接口&#…

从入门到精通:电商设计师的职业发展指南

在当今数字时代&#xff0c;电商设计师的作用越来越重要。从电子商务网站的整体造型设计到产品页面的具体布局&#xff0c;他们的工作范围是电子商务企业成功的关键因素之一。然而&#xff0c;并不是每个人都对这个职业有深刻的理解。因此&#xff0c;在本文中&#xff0c;我们…

web3d值得学习并长期发展,性价比高吗?

在数字化浪潮日益汹涌的今天&#xff0c;Web3D技术以其独特的魅力和广泛的应用前景&#xff0c;逐渐成为技术领域的焦点。对于许多热衷于技术探索和创新的人来说&#xff0c;学习并长期发展Web3D技术无疑是一个值得考虑的选择。那么&#xff0c;Web3D技术的学习和发展究竟是否性…

华为openEuler 24.03 LTS系统安装系统后用SSH工具不能连接

sudo dnf install vim #安装VIM vim /etc/ssh/sshd_config #修改文件如图systemctl restart sshd #重启服务再用SSH工具连接成功

【树莓派+OpenCV+STM32】智能小车巡线_提取线路数据并通过串口通信传输

一、所用材料 树莓派4B树莓派官方摄像头STM32F103C8T6最小系统板 二、实现功能 在树莓派上用OpenCV对摄像头中的图像进行处理&#xff0c;将图像处理后的数据通过串口通信给到下位机STM32F103C8T6&#xff0c;再由下位机给出控制信号&#xff0c;利用pid算法实现对小车运动轨…

备忘录系统

目录 一、 系统简介 1.简介 2需求分析 3 编程环境与工具 二、 系统总体设计 1 系统的功能模块图。 2 各功能模块简介 3项目结构 4 三、 主要业务流程 &#xff08;1&#xff09;用户及管理员登录流程图 &#xff08;2&#xff09;信息添加流程 &#xff0…

强烈推荐这三款IOS应用,让你的生活更美好

Dino记账 Dino记账是一款结合了简洁设计和强大功能的记账应用&#xff0c;它通过多维度图表帮助用户轻松掌握金钱流向。应用界面明亮且配色突出&#xff0c;使得记录内容易于阅读&#xff0c;让记账和管理账目变得更加简单。 主要特性&#xff1a; 极简风格与易用性&#xff1…

史上最全Spring的@Transactional不生效的12大场景

一、事务不生效 1、访问权限的问题 在Spring框架中&#xff0c;AbstractFallbackTransactionAttributeSource是用于确定一个给定的方法是否应该被事务管理的一个抽象类。它的computeTransactionAttribute方法用于计算并返回一个方法的TransactionAttribute。computeTransacti…

SD NAND存储卡:小尺寸下的大容量存储

SD NAND是一种基于NAND闪存技术的存储设备&#xff0c;采用SD卡形式&#xff0c;具备高存储容量、高速度和高可靠性的特点&#xff0c;广泛应用于嵌入式系统和消费电子产品中。 在如今数据驱动的世界&#xff0c;存储技术的发展至关重要。MK米客方德作为存储芯片行业的领先者&…

C++(week14): C++提高:(一)面向对象设计:设计原则、设计模式

文章目录 一、面向对象设计的概念4.统一建模语言&#xff1a;UML语言StartUML 二、类与类之间的关系0.总结(1)类与类的五种关系(2)区别(3)面向对象 vs 基于对象 1.继承 (泛化耦合)2.组合 (Composition)3.聚合 (Aggregation)4.关联(1)双向关联(2)单向关联 5.依赖 (Dependency) 三…

JNDI注入-RMI和Reference

参考博客&#xff1a; JNDI注入与动态类加载 JNDI Java命名和接口目录为用Java编程语言编写的应用程序提供命名和目录功能。 可以通过一种通用方式访问各种服务&#xff0c;类似通过名字查找对象的功能&#xff0c;和RMI有点类似。 原生JNDI支持RMI&#xff0c;LDAP&#…

2024最新前端学习路线指南!

2024最新前端学习路线指南&#xff01; 如果你正在寻找一份全面的前端学习路线图&#xff0c;那么这份精心打造的学习大纲恰好符合您的需求。无论您是新手还是经验丰富的开发者&#xff0c;这份路线图都能够帮助您系统地掌握前端开发的关键知识点&#xff0c;并在实践中不断提…

实验2-3-7 阶梯电价

//实验2-3-7 阶梯电价 /*为了提倡居民节约用电&#xff0c;某省电力公司执行“阶梯电价”&#xff0c; 安装一户一表的居民用户电价分为两个“阶梯”&#xff1a; 月用电量50千瓦时&#xff08;含50千瓦时&#xff09;以内的&#xff0c;电价为0.53元/千瓦时&#xff1b; 超过5…

java实现加水印功能

1-Word加水印 实现原理&#xff1a; ● 通过页眉页脚生成文字水印或图片水印&#xff0c;然后设置页眉页脚的高度以及旋转角度来设置水印。 源代码&#xff1a; 1、引入pom依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml…

家具购物小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;家具分类管理&#xff0c;家具新品管理&#xff0c;订单管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;家具新品&#xff0c;家具公告&#xff0…