手摸手教你撕碎西门子S7通讯协议04--S7COMM请求
创始人
2024-09-26 15:48:12
0

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     {         ///          /// plc的ip地址         ///          static string _ip = "192.168.1.66";         ///          /// 端口号         ///          static int _port = 102;         ///          /// 机柜号,插槽号         ///          static byte _rack = 0, _slot = 1;         ///          /// socket对象         ///          static Socket socket = null;         ///          /// 时间事件         ///          static ManualResetEvent TimeoutObject = new ManualResetEvent(false);         ///          /// 连接状态          ///          static bool connectState = false;         ///          /// 通讯连接的pdu长度         ///          static short _pduSize = 240;          static void Main(string[] args)         {             Connect();             if (connectState)             {                 COTPConnection();                 if (connectState)                 {                     SetupCommunication();                 }             }              Console.ReadKey();         }          ///          /// 通讯连接         ///          ///          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;         }          ///          /// cotp连接         ///          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;         }         ///          /// tcp连接          ///          ///          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对象通讯实现的,小伙伴们,明白了不?下节继续屌起来。

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

相关内容

热门资讯

总算了解!广西老友有破解吗,开... 总算了解!广西老友有破解吗,开心泉州免费辅助器,攻略教程(有挂分享)1、开心泉州免费辅助器有没有辅助...
无独有偶!微信小程序免费黑科技... 无独有偶!微信小程序免费黑科技透视,微乐小程序多功能修改器法子教程(有挂分享)1、这是跨平台的微乐小...
避坑细节!宝宝游戏辅助,决战卡... 避坑细节!宝宝游戏辅助,决战卡五星游戏辅助器,积累教程(有挂规律)亲,关键说明,决战卡五星游戏辅助器...
据权威媒体报道!微信小程序免费... 据权威媒体报道!微信小程序免费黑科技透视,钱塘十三水其实真的有挂手段教程(有挂详细)1、钱塘十三水其...
实测揭晓!同乡游辅助工具制作,... 实测揭晓!同乡游辅助工具制作,永胜联盟会封号吗,模块教程(有挂教学)1、同乡游辅助工具制作模拟器是什...
实测必看!微信小程序免费黑科技... 实测必看!微信小程序免费黑科技开挂,皮皮胡子辅助举措教程(有挂详细)1、起透看视 微信小程序免费黑科...
一分钟揭秘!微乐小程序免费黑科... 一分钟揭秘!微乐小程序免费黑科技安卓,新超凡软件辅助练习教程(有挂存在)1、微乐小程序免费黑科技脚本...
必备辅助推荐!蜜瓜大厅可以装挂... 必备辅助推荐!蜜瓜大厅可以装挂吗,友友联盟辅助脚本,指南书教程(有挂技术)1、进入游戏-大厅左侧-新...
今日焦点!微信小程序免费黑科技... 今日焦点!微信小程序免费黑科技透视,川南久久辅助模块教程(存在有挂)运微信小程序免费黑科技辅助工具,...
技术分享!山西扣点点辅助工具,... 技术分享!山西扣点点辅助工具,福州十八扑外卦视频,诀窍教程(有挂方法)1、山西扣点点辅助工具公共底牌...