IoTClient开发6 - S7-200SmarTcp协议客户端实现
环境和工具
服务端电脑IP:192.168.1.130
客户端电脑IP:192.168.1.120
1、在服务端电脑运行IoTClientTool

2、运行Wireshark

3、在客户端电脑运行IoTClientTool

4、Wireshark得到如下报文

报文分析,plc的连接
我们看到上面连接西门子plc抓取到了八条报文。其中有tcp的三次握手、和对最后一次响应的回复,然后就是西门子特有的两次初始化指令的请求和响应。

两次初始化指令
不同型号的西门子plc有不同的初始化指令,同型号的指令固定不变。

代码实现对plc的连接
//直接是Wireshark抓取到的报文数据
var Command1 = new byte[22]
{
0x03,0x00,0x00,0x16,0x11,0xE0,0x00,0x00,
0x00,0x01,0x00,0xC1,0x02,0x10,0x00,0xC2,
0x02,0x03,0x00,0xC0,0x01,0x0A
};
var Command2 = new byte[25]
{
0x03,0x00,0x00,0x19,0x02,0xF0,0x80,0x32,
0x01,0x00,0x00,0xCC,0xC1,0x00,0x08,0x00,
0x00,0xF0,0x00,0x00,0x01,0x00,0x01,0x03,0xC0
};
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(new IPEndPoint(IPAddress.Parse(ip), port));
//第一次初始化指令交互
socket.Send(Command1);
var head1 = SocketRead(socket, SiemensConstant.InitHeadLength);
SocketRead(socket, GetContentLength(head1));
//第二次初始化指令交互
socket.Send(Command2);
var head2 = SocketRead(socket, SiemensConstant.InitHeadLength);
SocketRead(socket, GetContentLength(head2));
对寄存器的读取
我们在客户端电用IoTClientTool读取地址V2634,抓取到包

我们可以看到其中很多都是固定的数据,如版本号、协议id等等。所以,我们可以以此规律获取对应的指令格式
protected byte[] GetReadCommand(byte type, int beginAddress, ushort dbAddress, ushort length)
{
byte[] command = new byte[31];
command[0] = 0x03;
command[1] = 0x00;//[0][1]固定报文头
command[2] = (byte)(command.Length / 256);
command[3] = (byte)(command.Length % 256);//[2][3]整个读取请求长度为0x1F= 31
command[4] = 0x02;
command[5] = 0xF0;
command[6] = 0x80;//COTP
command[7] = 0x32;//协议ID
command[8] = 0x01;//1 客户端发送命令 3 服务器回复命令
command[9] = 0x00;
command[10] = 0x00;//[4]-[10]固定6个字节
command[11] = 0x00;
command[12] = 0x01;//[11][12]两个字节,标识序列号,回复报文相同位置和这个完全一样;范围是0~65535
command[13] = 0x00;
command[14] = 0x0E;//parameter length([17]-[30]都为parameter刚好14也就是0x0E)
command[15] = 0x00;
command[16] = 0x00;//data length
command[17] = 0x04;//04读 05写
command[18] = 0x01;//读取数据块个数
command[19] = 0x12;//variable specification
command[20] = 0x0A;//Length of following address specification
command[21] = 0x10;//Syntax Id: S7ANY
command[22] = 0x02;//Transport size: BYTE
command[23] = (byte)(length / 256);
command[24] = (byte)(length % 256);//[23][24]两个字节,访问数据的个数,以byte为单位;
command[25] = (byte)(dbAddress / 256);
command[26] = (byte)(dbAddress % 256);//[25][26]DB块的编号
command[27] = type;//访问数据块的类型
command[28] = (byte)(beginAddress / 256 / 256);
command[29] = (byte)(beginAddress / 256);
command[30] = (byte)(beginAddress % 256);//[28][29][30]访问DB块的偏移量
return command;
}
读取数据
public Result<byte[]> ReadString(string address, ushort length)
{
Connect();
var result = new Result<byte[]>();
//发送读取信息
var arg = ConvertArg(address);
byte[] command = GetReadCommand(arg.TypeCode, arg.BeginAddress, arg.DbBlock, length);
result.Requst = string.Join(" ", command.Select(t => t.ToString("X2")));
var dataPackage = SendPackage(command);
byte[] requst = new byte[length];
Array.Copy(dataPackage, 25, requst, 0, length);
//Array.Copy(dataPackage, dataPackage.Length - length, requst, 0, length);
result.Response = string.Join(" ", dataPackage.Select(t => t.ToString("X2")));
result.Value = requst;
return result;
}
对寄存器的写入
我们在客户端电用IoTClientTool对地址V2634写入值666,抓取到包

我们可以以此规律获取对应的指令格式
protected byte[] GetWriteCommand(byte type, int beginAddress, ushort dbAddress, byte[] data)
{
byte[] command = new byte[35 + data.Length];
command[0] = 0x03;
command[1] = 0x00;//[0][1]固定报文头
command[2] = (byte)((35 + data.Length) / 256);
command[3] = (byte)((35 + data.Length) % 256);//[2][3]整个读取请求长度
command[4] = 0x02;
command[5] = 0xF0;
command[6] = 0x80;
command[7] = 0x32;//[4]-[7]固定数据
command[8] = 0x01;//1 客户端发送命令 3 服务器回复命令
command[9] = 0x00;
command[10] = 0x00;
command[11] = 0x00;
command[12] = 0x01;//[9]-[12]标识序列号
command[13] = 0x00;
command[14] = 0x0E;
command[15] = (byte)((4 + data.Length) / 256);
command[16] = (byte)((4 + data.Length) % 256);//[15][16]写入长度+4
command[17] = 0x05;//04读 05写
command[18] = 0x01;//写入数据块个数
command[19] = 0x12;
command[20] = 0x0A;
command[21] = 0x10;//[19]-[21]固定
command[22] = 0x02;//写入方式,1是按位,2是按字
command[23] = (byte)(data.Length / 256);
command[24] = (byte)(data.Length % 256);//写入数据个数
command[25] = (byte)(dbAddress / 256);
command[26] = (byte)(dbAddress % 256);//DB块的编号
command[27] = type;
command[28] = (byte)(beginAddress / 256 / 256 % 256); ;
command[29] = (byte)(beginAddress / 256 % 256);
command[30] = (byte)(beginAddress % 256);//[28][29][30]访问DB块的偏移量
command[31] = 0x00;
command[32] = 0x04;//04 byte(字节) 03bit(位)
command[33] = (byte)(data.Length * 8 / 256);
command[34] = (byte)(data.Length * 8 % 256);//按位计算出的长度
data.CopyTo(command, 35);
return command;
}
写入数据
public Result Write(string address, byte[] data)
{
if (!socket?.Connected ?? true) Connect();
Result result = new Result();
Array.Reverse(data);
//发送写入信息
var arg = ConvertArg(address);
byte[] command = GetWriteCommand(arg.TypeCode, arg.BeginAddress, arg.DbBlock, data);
result.Requst = string.Join(" ", command.Select(t => t.ToString("X2")));
var dataPackage = SendPackage(command);
result.Response = string.Join(" ", dataPackage.Select(t => t.ToString("X2")));
return result;
}
IoTClient中S7-200SmarTcp协议的使用
安装
Nuget安装 Install-Package IoTClient
或图形化安装

使用
//1、实例化客户端 - 输入正确的IP和端口
SiemensClient client = new SiemensClient(SiemensVersion.S7_200Smart, "127.0.0.1",102);
//2、写操作
client.Write("Q1.3", true);
client.Write("V2205", (short)11);
client.Write("V2209", 33);
//3、读操作
var value1 = client.ReadBoolean("Q1.3").Value;
var value2 = client.ReadInt16("V2205").Value;
var value3 = client.ReadInt32("V2209").Value;
//4、如果没有主动Open,则会每次读写操作的时候自动打开自动和关闭连接,这样会使读写效率大大减低。所以建议手动Open和Close。
client.Open();
//5、读写操作都会返回操作结果对象Result
var result = client.ReadInt16("V2205");
//5.1 读取是否成功(true或false)
var isSucceed = result.IsSucceed;
//5.2 读取失败的异常信息
var errMsg = result.Err;
//5.3 读取操作实际发送的请求报文
var requst = result.Requst;
//5.4 读取操作服务端响应的报文
var response = result.Response;
//5.5 读取到的值
var value3 = result.Value;
结束
- 同步至索引目录:《物联网基础组件IoTClient开发系列》
- 参考: https://m.baidu.com/mip/c/www.360doc.cn/mip/763580999.html
- 完整实现:https://github.com/zhaopeiym/IoTClient
IoTClient开发6 - S7-200SmarTcp协议客户端实现的更多相关文章
- IoTClient开发3 - ModBusTcp协议客户端实现
前言 进过前面两章的介绍,今天开始正式的实战. 进制转换 很多朋友对于进制转换可能是在刚学计算机的时候有接触,后来做高级语言开发可能就慢慢忘记了.我们做工控开发的时候需要经常进行进制转换,这里和大家一 ...
- IoTClient开发4 - ModBusTcp协议服务端模拟
前言 上篇我们实现了ModBusTcp协议的客户端读写,可是在很多时候编写业务代码之前是没有现场环境的.总不能在客户现场去写代码,或是蒙着眼睛写然后求神拜佛不出错,又或是在办公室部署一套硬件环境.怎么 ...
- IoTClient开发5 - ModBusRtu协议
前言 前面我们介绍了ModBusTcp协议.今天我们接着来介绍ModBusRtu协议.和ModBusTcp不同的是ModBusRtu基于串口通信,ModBusTcp是基于Tcp以太网通信. 所以我们在 ...
- 物联网基础组件IoTClient开发系列
系列目录 IoTClient开发1 - 你也可以写个聊天程序 IoTClient开发2 - 你也可以写个服务器 IoTClient开发3 - ModBusTcp协议客户端实现 IoTClient开发4 ...
- iOS开发网络篇—HTTP协议
iOS开发网络篇—HTTP协议 说明:apache tomcat服务器必须占用8080端口 一.URL 1.基本介绍 URL的全称是Uniform Resource Locator(统一资源定位符) ...
- 02.iOS开发网络篇—HTTP协议
iOS开发网络篇—HTTP协议 说明:apache tomcat服务器必须占用8080端口 一.URL 1.基本介绍 URL的全称是Uniform Resource Locator(统一资源定位符) ...
- 开源的C#实现WebSocket协议客户端和服务器websocket-sharp组件解析
很久没有写博客了(至少自己感觉很长时间没有写了),没办法啊,楼主也是需要生活的人啊,这段一直都在找工作什么的.(整天催我代码的人,还望多多谅解啊,我会坚持写我们的项目的,还是需要相信我的,毕竟这是一个 ...
- C#实现WebSocket协议客户端和服务器websocket sharp组件实例解析
看到这篇文章的题目,估计很多人都会问,这个组件是不是有些显的无聊了,说到web通信,很多人都会想到ASP.NET SignalR,或者Nodejs等等,实现web的网络实时通讯.有关于web实时通信的 ...
- 在 IBM RAD 平台上基于 JAX-WS 开发 Web Services服务器端,客户端
原文地址:https://www.ibm.com/developerworks/cn/websphere/library/techarticles/1305_jiangpl_rad/1305_jian ...
随机推荐
- Linq中带有迭代索引的Select扩展方法,为啥知道的人不多呢?
一:背景 昨天在看C#函数式编程这本书的时候,有一处让我干着急,需求是这样: 给多行文字加上数字列表项. 针对这个需求你会如何快捷高效的给每个项目加上数字编号呢? 我看书中是这样实现的,如下代码 pu ...
- STC15F2K60S2串口通信的应用。
前言:由于不可抗拒因素,初始的STC12C5A60S2芯片由于无法进行烧录(...因为没带有锁紧座的开发板),暂且使用STC15F2K60S2芯片.. 一 串行通信概述: 串口通信有SPI IIC U ...
- Git应用详解第十讲:Git子库:submodule与subtree.md
前言 前情提要:Git应用详解第九讲:Git cherry-pick与Git rebase 一个中大型项目往往会依赖几个模块,git提供了子库的概念.可以将这些子模块存放在不同的仓库中,通过submo ...
- 数字电路技术之触发器(基本RS触发器)
一.触发器的知识 1.触发器是构成时序逻辑电路的基本逻辑部件. 2.[1]它有两个稳定的状态:0状态和1状态: [2]在不同的输入情况下,它可以被置成0状态或1状态: [3]当输入 ...
- 用Taro做个微信小程序Todo, 小白工作记录
微信小程序框架: Taro 做微信小程序的框架, 几个比较主流的: 官方的WePY: https://tencent.github.io/wepy/document.html#/ 美团的mpvue: ...
- python调用小豆机器人实现自己的机器人!
大家好,人工智能是不是很酷呢? 今天我们用python调用小豆机器人实现自己的机器人(可以结合往期的语音识别更酷哦) 好,废话不多说直接上代码 import requests i=input(&quo ...
- react-devtools安装调试
初学react,Chrome F12调试,需要一款插件react-devtools. 网上大多对于翻墙不利索的同学大多才用了git源码.npm本地手动打包Chrome拓展程序.如:https://ww ...
- 《并发编程的艺术》阅读笔记之Lock与AQS
Lock接口 在jdk1.5之后,并发包下新增了一个lock接口,lock接口定义了锁的获取,锁的释放,等方法,需要用户手动设置.与关键字不同的是,lock具有可操作性,比如,可以中断线程,设置超时时 ...
- 关于如何在Linux上使用Nugix反向代理部署net core3.1项目
本文意在教大家如何在Linux上部署net core web项目,本人通过实践已经成功可以通过外网访问我部署在阿里云服务器上的站点. 一:需要用到的东西如下: 1:一个基于net core框架下的we ...
- Linux - centos7.X安装tomcat8
创建tomcat安装路径 mkdir /usr/local/tomcat wget直接下载tomcat8 注意,需要已经安装了wget命令 wget http://mirrors.estointern ...