首页 > 编程语言 >C# Modbut TCP 读写

C# Modbut TCP 读写

时间:2024-04-26 18:12:15浏览次数:22  
标签:tcpClient return C# RequestCache TCP Key Modbut ipAddress public

一、封装基本连接、读写。读写 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 服务端

 

标签:tcpClient,return,C#,RequestCache,TCP,Key,Modbut,ipAddress,public
From: https://www.cnblogs.com/hkzw/p/18160548

相关文章

  • Nacos 安全零信任实践
    作者:柳遵飞Nacos作为配置中心经常存储一些敏感信息,但是由于误用导致安全风险,最常见的主要是以下两个问题:1)Nacos暴露公网可以吗?不可以,因为Nacos定位是注册配置中心,是内部系统,不应该暴露到公网使用。2)不得已要开公网不开鉴权可以吗?不可以,开公网不开鉴权等同于裸奔,为黑客攻击......
  • Memory Layout of the C program
    reference:CompilationStepsandMemoryLayoutoftheCProgramStorageClassRAM明明断电会丢失数据,为什么初始化的全局变量存储在RAM?详细分析程序的存储TableofContentsMemoryLayoutoftheCProgramWhenyourunanyCprogram,itsexecutableimageis......
  • JDK源码分析-Vector
    概述Vector是Java集合中线程安全的动态数组,它也可以根据需要进行扩容和缩容,与ArrayList类似。但有一个重要的区别,Vector是同步的,也就是它的操作是线程安全的,在某些特定场景下是可以保证线程安全的,但同时也会带来性能损耗,因此在单线程环境通常还是推荐使用ArrayList。类图......
  • SystemVerilog -- 6.3 Interface ~ Modports
    在接口中定义带有方向的modport列表,以对模块内的接口访问施加某些限制。关键字指示方向的声明方式与模块内部一样。Syntaxmodport[identifer](input[port_list],output[port_list]);下面显示的是接口myInterface的定义,它有几个信号和两个声明。modportdut0本......
  • amCharts图像分类
    代码案例<!DOCTYPEhtml><html><head><scriptsrc="https://cdn.amcharts.com/lib/5/index.js"></script><scriptsrc="https://cdn.amcharts.com/lib/5/xy.js"></script><scriptsrc=&qu......
  • 车用MCU,R7F701320EAFP、R7F701321EAFP、R7F701322EAFP、R7F701323EAFP微控制器功耗低,
    RH850/P1M——适用于底盘系统的汽车用微控制器简介RH850/P1M微控制器功耗低,闪存容量高达2MB,RAM容量高达128KB,具有增强型电机控制定时器、CAN接口、SENT和PSI5等传感器数字接口以及锁定CPU、ECC、BIST(内置自检)和ECM(错误控制模块)等安全功能,适用于底盘系统。此外,仅2......
  • csv文件导出后身份证和电话号码以及统一社会信用代码等数字字段乱码处理
     第一步:新建表格  第二步:获取数据---》导入数据  第三步:导入数据 第四步:  选择列----文本           TRANSLATEwithxEnglishArabicHebrewPolishBulgarianHindiPortugueseCatalanHmongDawRomanian......
  • Apache RocketMQ ACL 2.0 全新升级
    作者:徒钟引言RocketMQ作为一款流行的分布式消息中间件,被广泛应用于各种大型分布式系统和微服务中,承担着异步通信、系统解耦、削峰填谷和消息通知等重要的角色。随着技术的演进和业务规模的扩大,安全相关的挑战日益突出,消息系统的访问控制也变得尤为重要。然而,RocketMQ现有的AC......
  • 1.关于Modbus TCP/RTU协议
    一、上位机C#与PLC通信1.通常情况下,需要与 PLC 工程师进行对接,并根据其编写的 PLC 程序去读写指定的寄存器。(PLC工程师提供地址表,然后C#通过Modbus读写寄存器或线圈开关)2.PLC 工程师负责编写 PLC 控制程序,其中定义了各个寄存器的功能和用途,以及与外部设备的交互逻辑。因此......
  • 实验三 软件测试—pycharm开发
    一、实验题目:软件测试二、实验目的1、熟悉开发环境下的自动化测试工具;2、利用自动化测试工具进行自动化单元测试。三、实验内容1、选择开发环境,IDEA或PYCHARM任选其一;2、基于所选择的开发环境实现对输入的n个整数进行排序的代码;3、对所编写代码设计测试用例;4、基于所选择的......