C# Modbut TCP 读写

一、封装基本连接、读写。读写 ReadHoldingRegisters ,当前有四种方案,现在只使用 ReadHoldingRegisters int 类型,需要其他方案自行新增。

    public class ModbusClient
    {
        private TcpClient? tcpClient;
        private IModbusMaster? modbusMaster;

        public DateTime LastConTime; // 最后连接时间
        public string Key;

        public bool Connect(string ipAddress, int port)
        {
            try
            {
                if(NetworkUtility.IsIPAndPortReachable(ipAddress, port))
                {
                    if (tcpClient != null && tcpClient.Connected)
                    {
                        IPEndPoint? remoteEndPoint = (IPEndPoint)tcpClient.Client.RemoteEndPoint;
                        if (remoteEndPoint != null && remoteEndPoint.Address.ToString() == ipAddress && remoteEndPoint.Port == port)
                        {
                            return true;
                        }
                        else
                        {
                            tcpClient = new TcpClient(ipAddress, port);
                            modbusMaster = new ModbusFactory().CreateMaster(tcpClient);
                        }
                    }
                    else
                    {
                        tcpClient = new TcpClient(ipAddress, port);
                        modbusMaster = new ModbusFactory().CreateMaster(tcpClient);
                    }

                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error connecting to Modbus TCP: " + ex.Message);
                return false;
            }
        }

        public void Disconnect()
        {
            if (tcpClient != null)
            {
                tcpClient.Close();
                tcpClient = null;
            }
            if (modbusMaster != null)
            {
                modbusMaster.Dispose();
            }
        }

        public bool IsConnetc()
        {
            if(tcpClient != null)
            {
                return tcpClient.Connected;
            }
            return false;
        }

        /// <summary>
        /// 读取数据
        /// </summary>
        /// <param name="slaveAddress">SlaveID</param>
        /// <param name="startAddress">读取的地址位</param>
        /// <param name="numberOfPoints">读取几位值</param>
        /// <returns></returns>
        public ushort[] ReadInputRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
        {
            ushort[] result = { ushort.Parse("999") };
            try
            {
                if(modbusMaster != null)
                {
                    return modbusMaster.ReadHoldingRegisters(slaveAddress, startAddress, numberOfPoints);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error reading input registers: " + ex.Message);
            }
            return result;
        }

        /// <summary>
        /// 写入数据
        /// </summary>
        /// <param name="slaveAddress">SlaveID</param>
        /// <param name="address">写入地址位</param>
        /// <param name="value">写入值</param>
        public void WriteSingleRegister(byte slaveAddress, ushort address, ushort value)
        {
            try
            {
                if(modbusMaster != null)
                {
                    modbusMaster.WriteSingleRegister(slaveAddress, address, value);
                }
            }
            catch (Exception ex)
            {
                LogHelp.LogHelp.NoRepeatLog($"WriteSingleRegister ERR ", ex,10);
            }
        }


    }
View Code

 

检测IP

    public class NetworkUtility
    {
        /// <summary>
        /// 判定IP是否OK
        /// </summary>
        /// <param name="ipAddress"></param>
        /// <returns></returns>
        public static bool IsPingable(string ipAddress)
        {
            try
            {
                Ping pingSender = new Ping();
                PingReply reply = pingSender.Send(ipAddress);
                return reply.Status == IPStatus.Success;
            }
            catch (Exception)
            {
                return false;
            }
        }
        

        /// <summary>
        /// 判定端口号是否OK
        /// </summary>
        /// <param name="ipAddress"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public static bool IsPortOpen(string ipAddress, int port)
        {
            try
            {
                using (TcpClient client = new TcpClient())
                {
                    client.Connect(ipAddress, port);
                    return true;
                }
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// IP端口号是否可以连接
        /// </summary>
        /// <param name="ipAddress"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public static bool IsIPAndPortReachable(string ipAddress, int port)
        {
            bool result = false;
            bool isPingable = IsPingable(ipAddress); 
            if(!isPingable)
            {
                LogHelp.LogHelp.NoRepeatLog($"PING {ipAddress} 失败。",null,30);
            }
            else
            {
                bool isPortOpen = IsPortOpen(ipAddress, port);
                if (!isPortOpen)
                {
                    LogHelp.LogHelp.NoRepeatLog($"PING {ipAddress} Port {port} 失败。", null, 30);
                }
                else
                {
                    result = true;
                }
            }
            return result;
        }
    }
View Code

 

 

二、使用方法

ModbusClient modbusClient = new ModbusClient();
 bool ConRestlt = modbusClient.Connect(_IP, _Port);
 if (ConRestlt)
{
      var read = modbusClient.ReadInputRegisters(1,0,1);
      modbusClient.WriteSingleRegister(1,0,2);
 }
View Code

 

三、如果使用以上方案,多线程的时候每次都要连接。那么则使用一下方案。将连接状态缓存,并且定时断开连接

缓存

    public class RequestCache
    {
        public static Dictionary<string, ModbusClient> ModbusTcpRequset { get; set; } = new Dictionary<string, ModbusClient>();

    }
View Code

 

 

    public class ModBusTcpConnect
    {
        /// <summary>
        /// 获取缓存中的连接状态,如果没有连接则尝试连接
        /// </summary>
        /// <param name="_IP"></param>
        /// <param name="_Port"></param>
        /// <returns></returns>
        public static ModbusClient ModBusTCPConnect(string _IP, int _Port)
        {

            ModbusClient result = new ModbusClient();
            try
            {
                string Key = $"{_IP}:{_Port}";
                if (RequestCache.ModbusTcpRequset.ContainsKey(Key))
                {
                    ModbusClient ModbusClientCache = RequestCache.ModbusTcpRequset[Key];
                    if (!ModbusClientCache.IsConnetc())
                    {
                        bool resiltCon = ModbusClientCache.Connect(_IP, _Port);
                    }
                    result = RequestCache.ModbusTcpRequset[Key];

                    if (result.IsConnetc())
                    {
                        RequestCache.ModbusTcpRequset[Key].LastConTime = DateTime.Now;
                    }
                }
                else
                {
                    ModbusClient modbusClient = new ModbusClient();
                    bool ConRestlt = modbusClient.Connect(_IP, _Port);

                    modbusClient.Key = Key;
                    result = modbusClient;
                    if(ConRestlt)
                    {
                        if (!RequestCache.ModbusTcpRequset.ContainsKey(Key))
                        {
                            RequestCache.ModbusTcpRequset.TryAdd(Key, modbusClient);
                            RequestCache.ModbusTcpRequset[Key].LastConTime = DateTime.Now;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelp.LogHelp.NoRepeatLog($"ModBusTCPConnect Err ", ex, 10);
            }
            return result;

        }

        /// <summary>
        /// 定时断开10分钟没有使用的连接
        /// </summary>
        public void CloseModBusTCPConnect()
        {
            try
            {
                while (true)
                {
                    if (RequestCache.ModbusTcpRequset != null)
                    {
                        List<ModbusClient> ModbusClientList = RequestCache.ModbusTcpRequset.Values.ToList();
                        DateTime dateNow = DateTime.Now;
                        foreach (ModbusClient item in ModbusClientList)
                        {
                            if ((dateNow - Convert.ToDateTime(item.LastConTime)).TotalSeconds > 60 * 10)
                            {
                                item.Disconnect();
                                if (RequestCache.ModbusTcpRequset.ContainsKey(item.Key))
                                {
                                    RequestCache.ModbusTcpRequset.Remove(item.Key);
                                }
                            }
                        }
                    }
                    Thread.Sleep(1000 * 10);
                }
            }
            catch (Exception ex)
            {
                LogHelp.LogHelp.NoRepeatLog($"CloseModBusTCPConnect Err ", ex, 10);
                throw;
            }
        }

         
    }
View Code

 

 

四、使用方案

            ModbusClient modbusClient = ModBusTcpConnect.ModBusTCPConnect(IP, Convert.ToInt32(Port));
              
            if (modbusClient.IsConnetc())
            {
                 byte slaveAddress = (byte)Convert.ToInt32(areaConfiguration.SlaveID);
                ushort startAddress = ushort.Parse(Address);
                ushort numberOfPoints = ushort.Parse(NumberOfPoints);

                ushort[] registerValues = modbusClient.ReadInputRegisters(slaveAddress, startAddress, numberOfPoints);
                if (registerValues != null)
                {
                    result = string.Join(" ", Array.ConvertAll(registerValues, x => x.ToString()));
                }
            }
View Code

 

五、使用Modbus Slave 工具作为服务端测试

 

1、配置基础信息

 

 

 2、自定义IP或者端口

 

 

 前面的序号就是 地址位 地址位的值默认是int类型

 

 软件下载地址 :https://wwt.lanzouo.com/ikutE1wlk8oh

 ModbusPollSetup 是服务端
ModbusSlaveSetup 是客户端
以上代码是客户端,我们需要安装的是 ModbusPollSetup 服务端

 

posted @ 2024-04-26 18:04  #青鸟爱吃鱼  阅读(83)  评论(0编辑  收藏  举报