ModbusTCP相信大家都很熟悉,在TCP基礎上封裝的一層應用協議,從串列埠ModbusRTU移植過來,不過tcp連線很靠譜,去掉了CRC校驗,我這裡實現的是4區,我個人而言比較常用,其他區用仿照這個改改功能碼就行,行了廢話少說,上程式碼不到200行。
using System;using System.Collections.Generic;using System.Linq;using System.Net;using System.Net.Sockets;using System.Text;using System.Threading;namespace WDBaseCommuntionHelper{ public class ModbusTCP { Socket ModbusTcpClient; ushort ID = 0; private byte[] MBAP = new byte[] { 00, 00, 00, 00, 00 }; bool connect; string ip; int port; public int MaxDelayCycle { get; set; } = 10; object lockModbus = new object(); public bool RestConnect() { return Connect(ip, port); } public bool Connect(string ip, int port) { this.ip = ip; this.port = port; if (ModbusTcpClient != null) { ModbusTcpClient.Close(); } ModbusTcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//建立sokcet tcp連線物件 IAsyncResult asyncResult = ModbusTcpClient.BeginConnect(new IPEndPoint(IPAddress.Parse(ip), port), null, null);//非同步連線 asyncResult.AsyncWaitHandle.WaitOne(3000, true);//阻塞最多等待3秒 if (!asyncResult.IsCompleted)//非同步操作沒完成 就關掉tcp連線 返回失敗 { ModbusTcpClient.Close(); connect = false; return false; } connect = true; return true; } public void DisConnect() { if (ModbusTcpClient != null) { ModbusTcpClient.Close(); } } public bool IsConnected{get{return connect;}} // MODBUS讀保持暫存器 //主站請求:00 00 00 00 00 06 00 03 00 00 00 01 //地址 1位元組(無意義,因為是TCP協議,在串列埠伺服器裡有意義) //功能碼 1位元組 0x03 批次讀資料 //起始暫存器地址 2位元組 //暫存器數量 2位元組 public byte[] ReadKeepReg(uint iAddress, int iLength) { byte[] SendCommand = new byte[12]; //ModbusTCP報文封裝 ID++; byte[] id = BitConverter.GetBytes(ID); SendCommand[0] = id[1]; //此次通訊事務處理識別符號2個位元組 SendCommand[1] = id[0]; SendCommand[2] = MBAP[2];//==00該指令遵循modbusTcp; 2個位元組 SendCommand[3] = MBAP[3]; SendCommand[4] = 00;//後面資料位元組長度 SendCommand[5] = 06; SendCommand[6] = 00;//站地址無 SendCommand[7] = 03;//功能碼 SendCommand[8] = (byte)((iAddress - iAddress % 256) / 256);//暫存器地址 2個位元組 SendCommand[9] = (byte)(iAddress % 256); SendCommand[10] = (byte)((iLength - iLength % 256) / 256);//暫存器個數 2個位元組 SendCommand[11] = (byte)(iLength % 256); byte[] ResByte = SendRecive(SendCommand); if (ResByte?.Length == 9 + iLength * 2 && ResByte[0] == SendCommand[0] && ResByte[1] == SendCommand[1] && ResByte[7] == 03 && ResByte[8] == iLength * 2) { byte[] userByte = new byte[iLength * 2]; for (int i = 0; i < userByte.Length; i++) { userByte[i] = ResByte[9 + i]; } return userByte; } return null; } /// <summary> /// 寫保持暫存器 /// </summary> /// <param name="iAddress">字地址</param> /// <param name="arry">要寫入的位元組陣列2的倍數</param> /// <returns></returns> public bool WriteKeepReg(int iAddress, byte[] arry) { byte byteCount = (byte)arry.Length; byte wordCount = (byte)(arry.Length / 2); int Conut = 7 + byteCount; byte[] SendCommand = new byte[13 + byteCount]; //ModbusTCP報文封裝 ID++; byte[] id = BitConverter.GetBytes(ID); SendCommand[0] = id[1]; //此次通訊事務處理識別符號2個位元組 SendCommand[1] = id[0]; SendCommand[2] = MBAP[2];//==00該指令遵循modbusTcp; 2個位元組 SendCommand[3] = MBAP[3]; SendCommand[4] = 0;//後面資料位元組長度 SendCommand[5] = (byte)Conut; SendCommand[6] = 0;//站地址無 SendCommand[7] = 0x10;//功能碼 SendCommand[8] = (byte)((iAddress - iAddress % 256) / 256);//起始暫存器地址 2個位元組 SendCommand[9] = (byte)(iAddress % 256); SendCommand[10] = 0;//寫暫存器數量 2個位元組 SendCommand[11] = wordCount; SendCommand[12] = byteCount;//寫暫存器個數 2個位元組(*2) for (int i = 0; i < byteCount; i++)//資料內容 { SendCommand[i + 13] = arry[i]; } byte[] ResByte = SendRecive(SendCommand); if (ResByte?.Length > 11 && ResByte[0] == SendCommand[0] && ResByte[1] == SendCommand[1] && ResByte[7] == 16 && ResByte[11] == arry.Length / 2)//報文正確判定 { return true; } return false; } public byte[] SendRecive(byte[] arry) { int delay = 0; try { Monitor.Enter(lockModbus); int reslut = ModbusTcpClient.Send(arry); while (ModbusTcpClient.Available == 0) { Thread.Sleep(10); delay++; if (delay > MaxDelayCycle) { break; } } byte[] ResByte = new byte[ModbusTcpClient.Available]; reslut = ModbusTcpClient.Receive(ResByte); return ResByte; } catch (Exception) { connect = false; return null; } finally { Monitor.Exit(lockModbus); } } }}
最新評論