環境和工具 服務端電腦IP:192.168.1.130 客戶端電腦IP:192.168.1.120 1、在服務端電腦運行 "IoTClientTool" 2、運行 "Wireshark" 3、在客戶端電腦運行 "IoTClientTool" 4、Wireshark得到如下報文 報文分析,plc的連接 ...
環境和工具
服務端電腦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