手摸手教你撕碎西门子S7通讯协议14--开发自己的通讯库读数据

news2024/12/25 9:00:10

1、S7通讯回顾


    - (1)建立TCP连接      Socket.Connect- 

     - (2)发送访问请求     COTP- 

     - (3)交换通信信息     Setup Communication- 

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

2、s7报文回顾 

1、CTOP请求连接

2、SetupCommunication通讯数据交换

3、S7COMM-Read报文

4、S7COMM-Write报文

3、第3方通讯库回顾 

S7.NET是一个广泛应用于.NET平台的西门子PLC通信库,在使用西门子PLC进行工业自动化控制的过程中,经常利用这个工具实现与PLC进行数据交换,它的方法通过上节操作应用可以看到格式是这样的,读取使用的命令是:plc.Read(varaddr),写入使用的命令是: plc.Write(varaddr, ts3),而我们的方法是一个个拼装字节数组,然后发送,然后解析报文,这对于应用者来说再痛苦了,能不能象第3方库那样,给个地址,调用命令就可以实现读取了,当然可以,这就是我们的目的,必须地强大武装起来,封装后的通讯库那是硬核,黄金。

 4、开始封装

1、创建项目

 

2、添加类库项目

 

  

3、创建基础类

 

 

 

4、封装连接的方法

 

 

 /// <summary>
 /// 建立连接:包括3步:1》tcp连接,2》COTP连接,3》通信连接
 /// </summary>
 /// <param name="timeout">超时时间</param>
 /// <returns></returns>
 public Result Connect(int timeout = 50)
 {
     TimeoutObject.Reset();
     Result result = new Result();
     try
     {
         if (socket == null)
             throw new Exception("通信对象未初始化");
         int count = 0;
         while (count < timeout)
         {
             // 第一步:建立tcp连接,即socket.Connected
             // 断线重连:
             // 1、被服务端主动踢掉(服务连接列表里已经没有当前客户端信息了)
             // 2、断网(拔网线)   客户端(不知道-》新的端口进行连接)、服务端(可以知道、检查客户端的心跳)
             if (!(!socket.Connected || (socket.Poll(200, SelectMode.SelectRead) && (socket.Available == 0))))
             {
                 return result;
             }
             try
             {
                 socket?.Close();
                 socket.Dispose();
                 socket = null;
                 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);
                 if (!connectState) throw new Exception();
                 else break;
             }
             catch (SocketException ex)
             {
                 if (ex.ErrorCode == 10060)
                     throw new Exception(ex.Message);
             }
             catch (Exception) { }
             finally
             {
                 count++;
             }
         }
         if (socket == null || !socket.Connected || ((socket.Poll(200, SelectMode.SelectRead) && (socket.Available == 0))))
         {
             throw new Exception("网络连接失败");
         }
         else
         {
             // 第二步:建立COTP连接请求
             result = COTPConnection();
             if (!result.IsSuccessed) return result;
             // 第三步:建立Setup通信
             result = SetupCommunication();
             if (!result.IsSuccessed) return result;
         }
     }
     catch (Exception ex)
     {
         result.IsSuccessed = false;
         result.Message = ex.Message;
     }
     return result;
 }

 /// <summary>
 /// 建立cotp连接 
 /// </summary>
 /// <returns></returns>
 private Result COTPConnection()
 {
     //COTP连接包括2个部分,共22个字节),22=4+18
     Result result = new Result();
     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)
         {
             throw new Exception("COTP连接响应异常");
         }
     }
     catch (Exception ex)
     {
         result.IsSuccessed = false;
         result.Message = "COTP连接未建立!" + ex.Message;
     }
     return result;
 }

 /// <summary>
 /// 建立通讯连接
 /// </summary>
 /// <returns></returns>
 private Result SetupCommunication()
 {
     //s7comm连接包括4个部分,共25个字节,即25=4+3+10+8
     Result result = new Result();
     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];
         this._pduSize = BitConverter.ToInt16(pdu_size,0);
     }
     catch (Exception ex)
     {
         result.IsSuccessed = false;
         result.Message = "Setup通信未建立!" + ex.Message;
     }
     return result;
 }

5、封装读取数据的方法


        /// <summary>
        /// 读取数据
        /// </summary>
        /// <typeparam name="T">返回值类型</typeparam>
        /// <param name="variable">变量地址</param>
        /// <param name="count">变量个数</param>
        /// <returns></returns>
        public Result<T> Read<T>(string variable, int count = 1)
        {
            DataParameter dataParameter = new DataParameter();
            Type mtype = typeof(T);

            try
            {
                dataParameter.GetFromVariable(variable);// 解析地址,最终是需要一个DataParameter
                if (mtype.Name == "Boolean")
                {
                    //dataParameter.ParamItemType = ParameterItemType.BIT;
                    dataParameter.DataItemType = DataItemType.BIT;
                }
                dataParameter.Count = count;

                // 获取数据
                return this.Read<T>(
                    dataParameter.ParamItemType,
                    dataParameter.DataItemType,
                    dataParameter.Count,
                    dataParameter.AreaType,
                    dataParameter.DBNumber,
                    dataParameter.ByteAddress,
                    dataParameter.BitAddress);
            }
            catch (Exception ex)
            {
                return new Result<T>(false, ex.Message);
            }
        }

6、添加项目引用

5、测试效果

先看下PLC的数据

1、读取浮点数

2、读取short数

3、读取bool数

 4、读取string

 

6、小结

 自己的通讯库是够甘甜的,和新疆的葡萄一样的香甜,有人可能要问,前面不是有第3方通讯库写好的,拉来用不就行了吗?是的,没有错,别人的东西可以拉来用,但是我们的目标不仅是使用,而是形成自己的产品,实力,别人的库也是写的代码,只是我们看不到而已。同样的,我们自己也可以,强国工程,从小做起,不得不来个大大的鸡腿,真香啊。

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

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

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

相关文章

【Android】DrawerLayout+NavigationView实现侧滑菜单页面

【Android】DrawerLayoutNavigationView实现侧滑菜单页面 在 Android 开发中&#xff0c;侧滑菜单是一个非常常见的用户界面模式&#xff0c;它能够在屏幕的一侧显示一个导航菜单&#xff0c;允许用户通过滑动手势或点击按钮来访问不同的应用功能。本文将介绍如何使用 DrawerL…

网页UI设计工具全攻略:九大精选

如果担心不知道如何进行网站 UI 设计、设计网站和编辑网页技术程序&#xff0c;很多人会选择快速方便的 Wix 建设。然而&#xff0c;如果你想建立一个最合适的网站&#xff0c;使用一个功能强大、资源丰富的网站 UI 设计工具仍然是您的最佳选择。网站设计中的 UI 设计不同于一般…

你是否知道Vue的data两种不同定义区别呢?

在做vue项目的时候&#xff0c;虽然vue3出来了一段时间了&#xff0c;vue2已经官方宣布不再维护了&#xff0c;然而我们有些旧项目原来是用的vue2的&#xff0c;那么用了那么久的vue2&#xff0c;不知道你是否有注意到&#xff0c;vue2我们往往会在根文件定义了一个对象形式的d…

类似redmine的项目管理系统有哪些?10款软件测评

国内外主流的10款类似redmine项目管理系统对比&#xff1a;PingCode、Worktile、TAPD、OpenProj、禅道&#xff08;ZenTao&#xff09;、Teambition、JIRA、Asana、Basecamp、Wrike。 在项目管理领域&#xff0c;选择一个既能满足需求又易于操作的工具是每个团队都面临的挑战。…

利用SOLIDWORKS CAD 2024新功能 提高团队工作效率

随着科技的不断发展&#xff0c;CAD&#xff08;计算机辅助设计&#xff09;软件在各行业中的应用越来越广泛&#xff0c;尤其在机械、汽车、航空航天、电子设备等领域。SOLIDWORKS作为一款功能强大的CAD软件&#xff0c;一直在不断更新和优化&#xff0c;以适应不断变化的市场…

【区块链】控制台的配置、操作及常用命令②

常用命令-账户管理 常用命令-区块信息 在控制台中编译部署智能合约 启动节点 在fisco目录下 bash nodes/127.0.0.1/start_all.sh启动控制台 cd ~/fisco/console && bash start.sh部署合约 deploy HelloWorldtransaction hash: 交易的哈希值 contract address&#x…

plugin ‘ROS2‘: loading...error CoppeliaSim和ROS2插件问题

问题 装了24年最新版本ROS2 Jazzy但是仿真软件打开出bug&#xff0c;怎么办&#xff1f; 等支持的出来&#xff0c;完全可以。但是&#xff0c;如果需要用&#xff0c;那调整一下即可。 CoppeliaSim&#xff08;V-Rep&#xff09;和ROS2的使用说明_coppeliasim编译-CSDN博客…

【网络】HTTP协议——应用层协议、URL、HTTP协议格式、HTTP的方法、HTTP的状态码、HTTP常见Header

文章目录 Linux网络1. 应用层2. HTTP协议2.1 URL2.2 urlencode和urdecode2.3 HTTP协议格式2.4 HTTP的方法2.5 HTTP的状态码2.6 HTTP常见Header Linux网络 1. 应用层 应用层是 OSI 七层模型或 TCP/IP 四层模型中的最高层&#xff0c;它直接为用户的应用程序提供服务。 应用层的…

MySQL数据库-SQL编程

一、触发器 1.触发器简介 触发器&#xff08;trigger&#xff09;是一个特殊的存储过程&#xff0c;它的执行不是由程序调用&#xff0c;也不是手工启动&#xff0c;而是由事件来触发&#xff0c;比如当对一个表进行操作&#xff08; insert&#xff0c;delete&#xff0c; u…

【C++标准库】模拟实现string类

模拟实现string类 一.命名空间与类成员变量二.构造函数1.无参&#xff08;默认&#xff09;构造2.有参构造3.兼容无参和有参构造4.拷贝构造1.传统写法2.现代写法 三.析构函数四.string类对象的容量操作1.size2.capacity3.clear4.empty5.reserve6.resize 五.string类对象的访问及…

傅里叶变换与FFT应用

一、傅里叶变换 1.1 变换 我们先给例子&#xff0c;假设在直角坐标系上有A(2,1),B(1,2);数和图之间存在的关系&#xff0c;称作变换&#xff1b;在图上我们想找对角线C&#xff0c;通过计算我们就知道C(3,3)&#xff1b;我们知道&#xff0c;在坐标系上有单位向量&#xff0c;…

Python 【机器学习】 进阶 之 【实战案例】房价数据中位数分析 之 [ 选择并训练模型 ] [ 模型微调 ] | 3/3(含分析过程)

Python 【机器学习】 进阶 之 【实战案例】房价数据中位数分析 之 [ 选择并训练模型 ] [ 模型微调 ] | 3/3&#xff08;含分析过程&#xff09; 目录 Python 【机器学习】 进阶 之 【实战案例】房价数据中位数分析 之 [ 选择并训练模型 ] [ 模型微调 ] | 3/3&#xff08;含分析…

Vue使用flex将图片并排居中且左对齐

先看效果&#xff1a; 在看代码 <template><div class"outer"><div class"inner"><div classeach_image v-for"(item,index) in image_list" :key"index"><img class"image_class" src"./…

培训孵化公司必备ERP的系统,跟卖和铺货以及订单物流发货打包

培训孵化必备的 ERP 系统&#xff0c;贴牌定制独立部署&#xff0c;跟卖铺货&#xff0c;物流对接。 说说新手与培训孵化学员如何使用 ERP&#xff01; 1. ERP 系统对于新手来说非常简单且容易操作&#xff0c;上面的跟卖功能很全面。比如铺货方面&#xff0c;可以采集 1688、…

发现SOLIDWORKS设计活页夹

您有没有遇到过将模型文件转交给同事时丢失附件的文档信息的&#xff1f;您有没有遇到过您的业务同事使用您的模型时仍然搞不清模型和业务项目之间的关系&#xff1f; 在纸制图纸的“旧时代”中&#xff0c;会有一整套信息&#xff08;文档或者表格&#xff09;与模型和图纸一…

电路原理--基础电路工具

1.正弦信号激励下的动态电路分析法-----频域相量法 课本第六章269页。 2.阻抗 3.滤波器简单理解 先介绍下滤波&#xff0c;芯片和元器件在相互工作的时候&#xff0c;会相互影响&#xff0c;在线路上产生寄生电阻或者寄生电容&#xff0c;这种现象叫耦合&#xff0c;耦合会带…

2024 巴黎奥运会:科技点亮体育盛会

一、引言 巴黎奥运会作为全球瞩目的体育盛事&#xff0c;承载着深厚的历史与文化底蕴。它不仅是运动员们展现卓越竞技能力的舞台&#xff0c;也是科技成果大放异彩的平台。科技在巴黎奥运会中的地位举足轻重&#xff0c;为赛事的各个方面带来了革新与突破。 从赛事的筹备到运…

Threejs中导入GLTF模型克隆后合并

很多场景中会需要同一个模型很多次&#xff0c;但是如果多次加载同一个模型会占用很高的带宽&#xff0c;导致加载很慢&#xff0c;因此就需要使用clone&#xff0c;也就是加载一个模型后&#xff0c;其他需要使用的地方使用clone的方式复制出多个同样的模型&#xff0c;再改变…

静态路由与默认路由和实验以及ARP工作原理

目录 1.静态路由和默认路由 1.1 静态路由 1.2 默认路由 1.3 主要区别总结 2.实验 2.1 实验 2.1.1 实验top 2.1.2 实验要求 2.2 实验配置 2.2.1 ip信息配置 2.2.2 配置静态 2.2.3配置默认 2.3 实验结果查看 3.为什么第一个ping会显示丢包&#xff1f; 3.1 ARP 工…