首頁>技術>

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);            }        }    }}

12
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 西門子S7協議抓包分析並用程式碼實現(四)