using System; using System.Collections.Generic; using System.Linq; using System.Text; using HslCommunication.Core; using HslCommunication; using HslCommunication.Core.Net; using System.Net.Sockets; namespace HslCommunication.ModBus { /// /// Modbus-tcp的虚拟服务器,支持线圈和寄存器的读写操作 /// public class ModbusTcpServer : NetworkServerBase { #region Constructor /// /// 实例化一个Modbus Tcp的服务器,支持数据读写操作 /// public ModbusTcpServer( ) { Coils = new bool[65536]; Register = new byte[65536 * 2]; hybirdLockCoil = new SimpleHybirdLock( ); hybirdLockRegister = new SimpleHybirdLock( ); lock_trusted_clients = new SimpleHybirdLock( ); subscriptions = new List( ); subcriptionHybirdLock = new SimpleHybirdLock( ); byteTransform = new ReverseWordTransform( ); } #endregion #region Private Method /// /// 判断操作线圈或是寄存器的是否发生了越界 /// /// 起始地址 /// 数据长度 /// 越界返回True,否则返回False private bool IsAddressOverBoundary( ushort address, ushort length ) { if ((address + length) >= ushort.MaxValue) { return true; } else { return false; } } #endregion #region Public Members /// /// 接收到数据的时候就行触发 /// public event Action OnDataReceived; #endregion #region Data Pool // 数据池,用来模拟真实的Modbus数据区块 private bool[] Coils; // 线圈池 private SimpleHybirdLock hybirdLockCoil; // 线圈池的同步锁 private byte[] Register; // 寄存器池 private SimpleHybirdLock hybirdLockRegister; // 寄存器池同步锁 private IByteTransform byteTransform; #endregion #region Coil Read Write /// /// 读取地址的线圈的通断情况 /// /// 起始地址 /// True或是False /// public bool ReadCoil( ushort address ) { bool result = false; hybirdLockCoil.Enter( ); result = Coils[address]; hybirdLockCoil.Leave( ); return result; } /// /// 批量读取地址的线圈的通断情况 /// /// 起始地址 /// 读取长度 /// True或是False /// public bool[] ReadCoil( ushort address, ushort length ) { bool[] result = new bool[length]; hybirdLockCoil.Enter( ); for (int i = address; i < address + length; i++) { if (i < ushort.MaxValue) { result[i - address] = Coils[i]; } } hybirdLockCoil.Leave( ); return result; } /// /// 写入线圈的通断值 /// /// 起始地址 /// 是否通断 /// True或是False /// public void WriteCoil( ushort address, bool data ) { hybirdLockCoil.Enter( ); Coils[address] = data; hybirdLockCoil.Leave( ); } /// /// 写入线圈数组的通断值 /// /// 起始地址 /// 是否通断 /// True或是False /// public void WriteCoil( ushort address, bool[] data ) { if (data == null) return; hybirdLockCoil.Enter( ); for (int i = address; i < address + data.Length; i++) { if (i < ushort.MaxValue) { Coils[i] = data[i - address]; } } hybirdLockCoil.Leave( ); } #endregion #region Register Read /// /// 读取自定义的寄存器的值 /// /// 起始地址 /// 数据长度 /// /// byte数组值 public byte[] ReadRegister( ushort address, ushort length ) { byte[] buffer = new byte[length * 2]; hybirdLockRegister.Enter( ); for (int i = 0; i < buffer.Length; i++) { buffer[i] = Register[address * 2 + i]; } hybirdLockRegister.Leave( ); return buffer; } /// /// 读取一个寄存器的值,返回类型short /// /// 起始地址 /// /// short值 public short ReadInt16( ushort address ) { return byteTransform.TransInt16( ReadRegister( address, 1 ), 0 ); } /// /// 批量读取寄存器的值 /// /// 起始地址 /// 读取的short长度 /// /// short数组值 public short[] ReadInt16( ushort address, ushort length ) { short[] result = new short[length]; for (int i = 0; i < length; i++) { result[i] = ReadInt16( (ushort)(address + i) ); } return result; } /// /// 读取一个寄存器的值,返回类型为ushort /// /// 起始地址 /// /// ushort值 public ushort ReadUInt16( ushort address ) { return byteTransform.TransUInt16( ReadRegister( address, 1 ), 0 ); } /// /// 批量读取寄存器的值 /// /// 起始地址 /// 读取长度 /// /// ushort数组 public ushort[] ReadUInt16( ushort address, ushort length ) { ushort[] result = new ushort[length]; for (int i = 0; i < length; i++) { result[i] = ReadUInt16( (ushort)(address + i) ); } return result; } /// /// 读取两个寄存器组成的int值 /// /// 起始地址 /// /// int值 public int ReadInt32( ushort address ) { return byteTransform.TransInt32( ReadRegister( address, 2 ), 0 ); } /// /// 批量读取寄存器组成的int值 /// /// 起始地址 /// 数组长度 /// /// int数组 public int[] ReadInt32( ushort address, ushort length ) { int[] result = new int[length]; for (int i = 0; i < length; i++) { result[i] = ReadInt32( (ushort)(address + 2 * i) ); } return result; } /// /// 读取两个寄存器组成的uint值 /// /// 起始地址 /// /// public uint ReadUInt32( ushort address ) { return byteTransform.TransUInt32( ReadRegister( address, 2 ), 0 ); } /// /// 批量读取寄存器组成的uint值 /// /// 起始地址 /// 数组长度 /// /// public uint[] ReadUInt32( ushort address, ushort length ) { uint[] result = new uint[length]; for (int i = 0; i < length; i++) { result[i] = ReadUInt32( (ushort)(address + 2 * i) ); } return result; } /// /// 读取两个寄存器组成的float值 /// /// 起始地址 /// /// public float ReadFloat( ushort address ) { return byteTransform.TransSingle( ReadRegister( address, 2 ), 0 ); } /// /// 批量读取寄存器组成的float值 /// /// 起始地址 /// 数组长度 /// /// public float[] ReadFloat( ushort address, ushort length ) { float[] result = new float[length]; for (int i = 0; i < length; i++) { result[i] = ReadFloat( (ushort)(address + 2 * i) ); } return result; } /// /// 读取四个寄存器组成的long值 /// /// 起始地址 /// /// public long ReadInt64( ushort address ) { return byteTransform.TransInt64( ReadRegister( address, 4 ), 0 ); } /// /// 批量读取寄存器组成的long值 /// /// 起始地址 /// 数组长度 /// /// public long[] ReadInt64( ushort address, ushort length ) { long[] result = new long[length]; for (int i = 0; i < length; i++) { result[i] = ReadInt64( (ushort)(address + 4 * i) ); } return result; } /// /// 读取四个寄存器组成的ulong值 /// /// 起始地址 /// /// public ulong ReadUInt64( ushort address ) { return byteTransform.TransUInt64( ReadRegister( address, 4 ), 0 ); } /// /// 批量读取寄存器组成的ulong值 /// /// 起始地址 /// 数组长度 /// /// public ulong[] ReadUInt64( ushort address, ushort length ) { ulong[] result = new ulong[length]; for (int i = 0; i < length; i++) { result[i] = ReadUInt64( (ushort)(address + 4 * i) ); } return result; } /// /// 读取四个寄存器组成的double值 /// /// 起始地址 /// /// public double ReadDouble( ushort address ) { return byteTransform.TransDouble( ReadRegister( address, 4 ), 0 ); } /// /// 批量读取寄存器组成的double值 /// /// 起始地址 /// 数组长度 /// /// public double[] ReadDouble( ushort address, ushort length ) { double[] result = new double[length]; for (int i = 0; i < length; i++) { result[i] = ReadDouble( (ushort)(address + 4 * i) ); } return result; } /// /// 读取ASCII字符串,长度为寄存器数量,最终的字符串长度为这个值的2倍 /// /// 起始地址 /// 寄存器长度 /// /// public string ReadString( ushort address, ushort length ) { string str = string.Empty; hybirdLockRegister.Enter( ); str = Encoding.ASCII.GetString( Register, address * 2, length * 2 ); hybirdLockRegister.Leave( ); return str; } #endregion #region Register Write /// /// 写入寄存器数据,指定字节数据 /// /// 起始地址 /// 字节数据 public void Write( ushort address, byte[] value ) { hybirdLockRegister.Enter( ); for (int i = 0; i < value.Length; i++) { Register[address * 2 + i] = value[i]; } hybirdLockRegister.Leave( ); } /// /// 写入寄存器数据,指定字节数据 /// /// 起始地址 /// 高位数据 /// 地位数据 public void Write( ushort address, byte high, byte low ) { Write( address, new byte[] { high, low } ); } /// /// 往Modbus服务器中的指定寄存器写入数据 /// /// 起始地址 /// 数据值 public void Write( ushort address, short value ) { Write( address, byteTransform.TransByte( value ) ); } /// /// 往Modbus服务器中的指定寄存器写入数组 /// /// 起始地址 /// 数据值 public void Write( ushort address, short[] value ) { if (value == null) return; Write( address, byteTransform.TransByte( value ) ); } /// /// 往Modbus服务器中的指定寄存器写入数据 /// /// 起始地址 /// 数据值 public void Write( ushort address, ushort value ) { Write( address, byteTransform.TransByte( value ) ); } /// /// 往Modbus服务器中的指定寄存器写入数组 /// /// 起始地址 /// 数据值 public void Write( ushort address, ushort[] value ) { if (value == null) return; Write( address, byteTransform.TransByte( value ) ); } /// /// 往Modbus服务器中的指定寄存器写入数据 /// /// 起始地址 /// 数据值 public void Write( ushort address, int value ) { Write( address, byteTransform.TransByte( value ) ); } /// /// 往Modbus服务器中的指定寄存器写入数组 /// /// 起始地址 /// 数据值 public void Write( ushort address, int[] value ) { if (value == null) return; Write( address, byteTransform.TransByte( value ) ); } /// /// 往Modbus服务器中的指定寄存器写入数据 /// /// 起始地址 /// 数据值 public void Write( ushort address, uint value ) { Write( address, byteTransform.TransByte( value ) ); } /// /// 往Modbus服务器中的指定寄存器写入数组 /// /// 起始地址 /// 数据值 public void Write( ushort address, uint[] value ) { if (value == null) return; Write( address, byteTransform.TransByte( value ) ); } /// /// 往Modbus服务器中的指定寄存器写入数据 /// /// 起始地址 /// 数据值 public void Write( ushort address, float value ) { Write( address, byteTransform.TransByte( value ) ); } /// /// 往Modbus服务器中的指定寄存器写入数组 /// /// 起始地址 /// 数据值 public void Write( ushort address, float[] value ) { if (value == null) return; Write( address, byteTransform.TransByte( value ) ); } /// /// 往Modbus服务器中的指定寄存器写入数据 /// /// 起始地址 /// 数据值 public void Write( ushort address, long value ) { Write( address, byteTransform.TransByte( value ) ); } /// /// 往Modbus服务器中的指定寄存器写入数组 /// /// 起始地址 /// 数据值 public void Write( ushort address, long[] value ) { if (value == null) return; Write( address, byteTransform.TransByte( value ) ); } /// /// 往Modbus服务器中的指定寄存器写入数据 /// /// 起始地址 /// 数据值 public void Write( ushort address, ulong value ) { Write( address, byteTransform.TransByte( value ) ); } /// /// 往Modbus服务器中的指定寄存器写入数组 /// /// 起始地址 /// 数据值 public void Write( ushort address, ulong[] value ) { if (value == null) return; Write( address, byteTransform.TransByte( value ) ); } /// /// 往Modbus服务器中的指定寄存器写入数据 /// /// 起始地址 /// 数据值 public void Write( ushort address, double value ) { Write( address, byteTransform.TransByte( value ) ); } /// /// 往Modbus服务器中的指定寄存器写入数组 /// /// 起始地址 /// 数据值 public void Write( ushort address, double[] value ) { if (value == null) return; Write( address, byteTransform.TransByte( value ) ); } /// /// 往Mobus服务器中的指定寄存器写入字符串 /// /// 其实地址 /// ASCII编码的字符串的信息 public void Write(ushort address, string value) { Write( address, byteTransform.TransByte( value ) ); } #endregion #region NetServer Override /// /// 当接收到了新的请求的时候执行的操作 /// /// protected override void ThreadPoolLogin( object obj ) { // 为了提高系统的响应能力,采用异步来实现,即时有数万台设备接入也能应付 if (obj is Socket) { Socket socket = obj as Socket; ModBusState state = new ModBusState( ) { WorkSocket = socket, }; try { state.IpEndPoint = (System.Net.IPEndPoint)socket.RemoteEndPoint; state.IpAddress = state.IpEndPoint.Address.ToString( ); } catch (Exception ex) { LogNet?.WriteException( ToString( ), "Ip信息获取失败", ex ); } if(IsTrustedClientsOnly) { // 检查受信任的情况 if(!CheckIpAddressTrusted( state.IpAddress )) { // 客户端不被信任,退出 LogNet?.WriteDebug( ToString( ), $"客户端 [ {state.IpEndPoint} ] 不被信任,禁止登录!" ); state.WorkSocket.Close( ); return; } } LogNet?.WriteDebug( ToString( ), $"客户端 [ {state.IpEndPoint} ] 上线" ); try { state.WorkSocket.BeginReceive( state.HeadByte, 0, 6, SocketFlags.None, new AsyncCallback( ModbusHeadReveiveCallback ), state ); } catch (Exception ex) { state = null; state.WorkSocket.Close( ); LogNet?.WriteException( ToString(), $"客户端 [ {state.IpEndPoint} ] 头子节接收失败!", ex ); } } } #endregion #region Private Method /// /// 检测当前的Modbus接收的指定是否是合法的 /// /// /// private bool CheckModbusMessageLegal( byte[] buffer ) { if (buffer[7] == 0x01 || buffer[7] == 0x02 || buffer[7] == 0x03 || buffer[7] == 0x05 || buffer[7] == 0x06) { if (buffer.Length != 0x0C) { return false; } else { return true; } } else if (buffer[7] == 0x0F || buffer[7] == 0x10) { if (buffer.Length < 13) { return false; } else { if (buffer[12] == (buffer.Length - 13)) { return true; } else { return false; } } } else { return true; } } private void ModbusHeadReveiveCallback( IAsyncResult ar ) { if (ar.AsyncState is ModBusState) { ModBusState state = ar.AsyncState as ModBusState; try { int receiveCount = state.WorkSocket.EndReceive( ar ); if (receiveCount == 0) { state.WorkSocket?.Close( ); LogNet?.WriteDebug( ToString( ), $"客户端 [ {state.IpEndPoint} ] 下线" ); return; } else { state.HeadByteReceivedLength += receiveCount; } } catch (Exception ex) { // 关闭连接,记录日志 state.WorkSocket?.Close( ); LogNet?.WriteException( ToString(), $"客户端 [ {state.IpEndPoint} ] 异常下线,消息子节接收失败!", ex ); return; } try { if (state.HeadByteReceivedLength < state.HeadByte.Length) { // 数据不够,继续接收 state.WorkSocket.BeginReceive( state.HeadByte, state.HeadByteReceivedLength, state.HeadByte.Length - state.HeadByteReceivedLength, SocketFlags.None, new AsyncCallback( ModbusHeadReveiveCallback ), state ); return; } } catch(Exception ex) { state.WorkSocket?.Close( ); LogNet?.WriteException( ToString( ), $"客户端 [ {state.IpEndPoint} ] 异常下线,再次启动接收失败!", ex ); return; } // 准备接收的数据长度 int ContentLength = state.HeadByte[4] * 256 + state.HeadByte[5]; // 第一次过滤,过滤掉不是Modbus Tcp协议的 if (state.HeadByte[2] == 0x00 && state.HeadByte[3] == 0x00 && ContentLength < 300) { try { // 头子节接收完成 state.Content = new byte[ContentLength]; state.ContentReceivedLength = 0; // 开始接收内容 state.WorkSocket.BeginReceive( state.Content, state.ContentReceivedLength, state.Content.Length - state.ContentReceivedLength, SocketFlags.None, new AsyncCallback( ModbusDataReveiveCallback ), state ); } catch(Exception ex) { state.WorkSocket?.Close( ); LogNet?.WriteException( ToString( ), $"客户端 [ {state.IpEndPoint} ] 异常下线,启动内容接收失败!", ex ); return; } } else { // 关闭连接,记录日志 state.WorkSocket?.Close(); LogNet?.WriteWarn(ToString(), $"客户端 [ {state.IpEndPoint} ] 下线,不是标准的Modbus协议!"); } } } private void ModbusDataReveiveCallback( IAsyncResult ar ) { if (ar.AsyncState is ModBusState) { ModBusState state = ar.AsyncState as ModBusState; try { state.ContentReceivedLength += state.WorkSocket.EndReceive( ar ); if (state.ContentReceivedLength < state.Content.Length) { // 数据不够,继续接收 state.WorkSocket.BeginReceive( state.Content, state.ContentReceivedLength, state.Content.Length - state.ContentReceivedLength, SocketFlags.None, new AsyncCallback( ModbusDataReveiveCallback ), state ); return; } } catch (Exception ex) { // 关闭连接,记录日志 state.WorkSocket?.Close( ); LogNet?.WriteException( ToString(), $"客户端 [ {state.IpEndPoint} ] 下线,内容数据接收失败!", ex ); return; } // 数据接收完成 // 内容接收完成,所有的数据接收结束 byte[] data = new byte[state.HeadByte.Length + state.Content.Length]; state.HeadByte.CopyTo( data, 0 ); state.Content.CopyTo( data, state.HeadByte.Length ); state.Clear( ); if (!CheckModbusMessageLegal( data )) { // 指令长度验证错误,关闭网络连接 state.WorkSocket?.Close( ); LogNet?.WriteError( ToString( ), $"客户端 [ {state.IpEndPoint} ] 下线,消息长度检查失败!" ); return; } // 需要回发消息 byte[] copy = null; switch (data[7]) { case ModbusInfo.ReadCoil: { copy = ReadCoilBack( data ); break; } case ModbusInfo.ReadRegister: { copy = ReadRegisterBack( data ); break; } case ModbusInfo.WriteOneCoil: { copy = WriteOneCoilBack( data ); break; } case ModbusInfo.WriteOneRegister: { copy = WriteOneRegisterBack( data ); break; } case ModbusInfo.WriteCoil: { copy = WriteCoilsBack( data ); break; } case ModbusInfo.WriteRegister: { copy = WriteRegisterBack( data ); break; } default: { copy = CreateExceptionBack( data, ModbusInfo.FunctionCodeNotSupport ); break; } } try { // 管他是什么,先开始数据接收 // state.WorkSocket?.Close(); state.WorkSocket.BeginReceive( state.HeadByte, 0, 6, SocketFlags.None, new AsyncCallback( ModbusHeadReveiveCallback ), state ); } catch (Exception ex) { state.WorkSocket?.Close( ); LogNet?.WriteException( ToString( ), $"客户端 [ {state.IpEndPoint} ] 异常下线,重新接收消息失败!", ex ); return; } // 回发数据,先获取发送锁 state.hybirdLock.Enter( ); try { state.WorkSocket.BeginSend( copy, 0, size: copy.Length, socketFlags: SocketFlags.None, callback: new AsyncCallback( DataSendCallBack ), state: state ); } catch(Exception ex) { state.WorkSocket?.Close( ); state.hybirdLock.Leave( ); LogNet?.WriteException( ToString( ), $"客户端 [ {state.IpEndPoint} ] 异常下线,开始回发消息失败!", ex ); return; } // 通知处理消息 if (IsStarted) OnDataReceived?.Invoke( data ); } } private void DataSendCallBack( IAsyncResult ar ) { if (ar.AsyncState is ModBusState) { ModBusState state = ar.AsyncState as ModBusState; state.hybirdLock.Leave( ); try { state.WorkSocket.EndSend( ar ); } catch (Exception ex) { state.WorkSocket?.Close( ); state = null; LogNet?.WriteException( ToString( ), $"客户端 [ {state.IpEndPoint} ] 异常下线,确认回发消息失败!", ex ); } } } #endregion #region Function Process Center /// /// 创建特殊的功能标识,然后返回该信息 /// /// /// /// private byte[] CreateExceptionBack( byte[] modbus, byte error ) { byte[] buffer = new byte[9]; Array.Copy( modbus, 0, buffer, 0, 7 ); buffer[4] = 0x00; buffer[5] = 0x03; buffer[7] = (byte)(modbus[7] + 0x80); buffer[8] = error; return buffer; } /// /// 创建返回消息 /// /// /// /// private byte[] CreateReadBack( byte[] modbus, byte[] content ) { byte[] buffer = new byte[9 + content.Length]; Array.Copy( modbus, 0, buffer, 0, 8 ); buffer[4] = (byte)((buffer.Length - 6) / 256); buffer[5] = (byte)((buffer.Length - 6) % 256); buffer[8] = (byte)content.Length; Array.Copy( content, 0, buffer, 9, content.Length ); return buffer; } /// /// 创建写入成功的反馈信号 /// /// /// private byte[] CreateWriteBack(byte[] modbus) { byte[] buffer = new byte[12]; Array.Copy( modbus, 0, buffer, 0, 12 ); buffer[4] = 0x00; buffer[5] = 0x06; return buffer; } private byte[] ReadCoilBack(byte[] modbus ) { try { ushort address = byteTransform.TransUInt16( modbus, 8 ); ushort length = byteTransform.TransUInt16( modbus, 10 ); // 越界检测 if ((address + length) >= ushort.MaxValue) { return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeOverBound ); } // 地址长度检测 if(length > 2040) { return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeQuantityOver ); } bool[] read = ReadCoil( address, length ); byte[] buffer = BasicFramework.SoftBasic.BoolArrayToByte( read ); return CreateReadBack( modbus, buffer ); } catch(Exception ex) { LogNet?.WriteException( ToString( ), StringResources.ModbusTcpReadCoilException, ex ); return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeReadWriteException ); } } private byte[] ReadRegisterBack(byte[] modbus) { try { ushort address = byteTransform.TransUInt16( modbus, 8 ); ushort length = byteTransform.TransUInt16( modbus, 10 ); // 越界检测 if ((address + length) >= ushort.MaxValue) { return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeOverBound ); } // 地址长度检测 if (length > 127) { return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeQuantityOver ); } byte[] buffer = ReadRegister( address, length ); return CreateReadBack( modbus, buffer ); } catch (Exception ex) { LogNet?.WriteException( ToString( ), StringResources.ModbusTcpReadRegisterException, ex ); return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeReadWriteException ); } } private byte[] WriteOneCoilBack( byte[] modbus ) { try { ushort address = byteTransform.TransUInt16( modbus, 8 ); if (modbus[10] == 0xFF && modbus[11] == 0x00) { WriteCoil( address, true ); } else if (modbus[10] == 0x00 && modbus[11] == 0x00) { WriteCoil( address, false ); } return CreateWriteBack( modbus ); } catch(Exception ex) { LogNet?.WriteException( ToString( ), StringResources.ModbusTcpWriteCoilException, ex ); return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeReadWriteException ); } } private byte[] WriteOneRegisterBack( byte[] modbus) { try { ushort address = byteTransform.TransUInt16( modbus, 8 ); short ValueOld = ReadInt16( address ); // 写入到寄存器 Write( address, modbus[10], modbus[11] ); short ValueNew = ReadInt16( address ); // 触发写入请求 OnRegisterBeforWrite( address, ValueOld, ValueNew ); return CreateWriteBack( modbus ); } catch(Exception ex) { LogNet?.WriteException( ToString( ), StringResources.ModbusTcpWriteRegisterException, ex ); return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeReadWriteException ); } } private byte[] WriteCoilsBack(byte[] modbus) { try { ushort address = byteTransform.TransUInt16( modbus, 8 ); ushort length = byteTransform.TransUInt16( modbus, 10 ); if ((address + length) > ushort.MaxValue) { return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeOverBound ); } if(length > 2040) { return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeQuantityOver ); } byte[] buffer = new byte[modbus.Length - 13]; Array.Copy( modbus, 13, buffer, 0, buffer.Length ); bool[] value = BasicFramework.SoftBasic.ByteToBoolArray( buffer, length ); WriteCoil( address, value ); return CreateWriteBack( modbus ); } catch (Exception ex) { LogNet?.WriteException( ToString( ), StringResources.ModbusTcpWriteCoilException, ex ); return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeReadWriteException ); } } private byte[] WriteRegisterBack( byte[] modbus) { try { ushort address = byteTransform.TransUInt16( modbus, 8 ); ushort length = byteTransform.TransUInt16( modbus, 10 ); if ((address + length) > ushort.MaxValue) { return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeOverBound ); } if (length > 127) { return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeQuantityOver ); } byte[] buffer = new byte[modbus.Length - 13]; // 为了使服务器的数据订阅更加的准确,决定将设计改为等待所有的数据写入完成后,再统一触发订阅,2018年3月4日 20:56:47 MonitorAddress[] addresses = new MonitorAddress[length]; for (ushort i = 0; i < length; i++) { short ValueOld = ReadInt16( (ushort)(address + i) ); Write( (ushort)(address + i), modbus[2 * i + 13], modbus[2 * i + 14] ); short ValueNew = ReadInt16( (ushort)(address + i) ); // 触发写入请求 addresses[i] = new MonitorAddress( ) { Address = (ushort)(address + i), ValueOrigin = ValueOld, ValueNew = ValueNew }; } // 所有数据都更改完成后,再触发消息 for (int i = 0; i < addresses.Length; i++) { OnRegisterBeforWrite( addresses[i].Address, addresses[i].ValueOrigin, addresses[i].ValueNew ); } return CreateWriteBack( modbus ); } catch (Exception ex) { LogNet?.WriteException( ToString( ), StringResources.ModbusTcpWriteRegisterException, ex ); return CreateExceptionBack( modbus, ModbusInfo.FunctionCodeReadWriteException ); } } #endregion #region Subscription Support // 本服务器端支持指定地址的数据订阅器,目前仅支持寄存器操作 private List subscriptions; // 数据订阅集合 private SimpleHybirdLock subcriptionHybirdLock; // 集合锁 /// /// 新增一个数据监视的任务,针对的是寄存器 /// /// public void AddSubcription( ModBusMonitorAddress monitor ) { subcriptionHybirdLock.Enter( ); subscriptions.Add( monitor ); subcriptionHybirdLock.Leave( ); } /// /// 移除一个数据监视的任务 /// /// public void RemoveSubcrption( ModBusMonitorAddress monitor ) { subcriptionHybirdLock.Enter( ); subscriptions.Remove( monitor ); subcriptionHybirdLock.Leave( ); } /// /// 在数据变更后,进行触发是否产生订阅 /// /// 数据地址 /// /// private void OnRegisterBeforWrite( ushort address, short before, short after ) { subcriptionHybirdLock.Enter( ); for (int i = 0; i < subscriptions.Count; i++) { if (subscriptions[i].Address == address) { subscriptions[i].SetValue( after ); if (before != after) { subscriptions[i].SetChangeValue( before, after ); } } } subcriptionHybirdLock.Leave( ); } #endregion #region Trust Client Only private List TrustedClients = null; // 受信任的客户端 private bool IsTrustedClientsOnly = false; // 是否启用仅仅受信任的客户端登录 private SimpleHybirdLock lock_trusted_clients; // 受信任的客户端的列表 /// /// 设置并启动受信任的客户端登录并读写,如果为null,将关闭对客户端的ip验证 /// /// 受信任的客户端列表 public void SetTrustedIpAddress(List clients) { lock_trusted_clients.Enter( ); if (clients != null) { TrustedClients = clients.Select( m => { System.Net.IPAddress iPAddress = System.Net.IPAddress.Parse( m ); return iPAddress.ToString( ); } ).ToList( ); IsTrustedClientsOnly = true; } else { TrustedClients = new List( ); IsTrustedClientsOnly = false; } lock_trusted_clients.Leave( ); } /// /// 检查该Ip地址是否是受信任的 /// /// Ip地址信息 /// 是受信任的返回True,否则返回False private bool CheckIpAddressTrusted(string ipAddress) { if(IsTrustedClientsOnly) { bool result = false; lock_trusted_clients.Enter( ); for (int i = 0; i < TrustedClients.Count; i++) { if(TrustedClients[i] == ipAddress) { result = true; break; } } lock_trusted_clients.Leave( ); return result; } else { return false; } } /// /// 获取受信任的客户端列表 /// /// public string[] GetTrustedClients() { string[] result = new string[0]; lock_trusted_clients.Enter( ); if(TrustedClients != null) { result = TrustedClients.ToArray( ); } lock_trusted_clients.Leave( ); return result; } #endregion #region Object Override /// /// 获取本对象的字符串表示形式 /// /// public override string ToString( ) { return "ModbusTcpServer"; } #endregion } }