private byte[] WriteRegisterBack(byte[] modbus) { try { ushort address = ByteTransform.TransUInt16(modbus, 2); ushort length = ByteTransform.TransUInt16(modbus, 4); if ((address + length) > ushort.MaxValue + 1) { return(CreateExceptionBack(modbus, ModbusInfo.FunctionCodeOverBound)); } if (length > 127) { return(CreateExceptionBack(modbus, ModbusInfo.FunctionCodeQuantityOver)); } byte[] buffer = new byte[modbus.Length - 7]; // 为了使服务器的数据订阅更加的准确,决定将设计改为等待所有的数据写入完成后,再统一触发订阅,2018年3月4日 20:56:47 MonitorAddress[] addresses = new MonitorAddress[length]; for (ushort i = 0; i < length; i++) { short ValueOld = ReadInt16((address + i).ToString( )).Content; Write((address + i).ToString( ), modbus[2 * i + 7], modbus[2 * i + 8]); short ValueNew = ReadInt16((address + i).ToString( )).Content; // 触发写入请求 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.Language.ModbusTcpWriteRegisterException, ex); return(CreateExceptionBack(modbus, ModbusInfo.FunctionCodeReadWriteException)); } }
private void ModbusDataReveiveCallback(IAsyncResult ar) { if (ar.AsyncState is ModBusState state) { try { state.ContentReceivedLength += state.WorkSocket.EndReceive(ar); } catch (Exception ex) { // 关闭连接,记录日志 state.WorkSocket?.Close(); state = null; LogNet?.WriteException(LogHeaderText, "内容数据接收失败!", ex); return; } 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; } // 数据接收完成 // 内容接收完成,所有的数据接收结束 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 (data[7] == 0x01 || data[7] == 0x02 || data[7] == 0x03) { if (data.Length != 0x0C) { // 指令长度验证错误,关闭网络连接 state.WorkSocket?.Close(); state = null; LogNet?.WriteWarn(LogHeaderText, "Command length check failed!"); return; } } // 需要回发消息 byte[] copy = null; try { switch (data[7]) { case 0x01: { // 线圈读取 int address = data[8] * 256 + data[9]; int length = data[10] * 256 + data[11]; if (length > 2048) { length = 2048; // 线圈读取应该小于2048个 } bool[] read = ReadCoil((ushort)address, (ushort)length); byte[] buffer = BasicFramework.SoftBasic.BoolArrayToByte(read); copy = new byte[9 + buffer.Length]; Array.Copy(data, 0, copy, 0, 8); copy[4] = (byte)((copy.Length - 6) / 256); copy[5] = (byte)((copy.Length - 6) % 256); copy[8] = (byte)buffer.Length; Array.Copy(buffer, 0, copy, 9, buffer.Length); break; } case 0x03: { // 寄存器读取 int address = data[8] * 256 + data[9]; int length = data[10] * 256 + data[11]; if (length > 127) { length = 127; // 寄存器最大读取范围为127个 } byte[] buffer = ReadRegister((ushort)address, (ushort)length); copy = new byte[9 + buffer.Length]; Array.Copy(data, 0, copy, 0, 8); copy[4] = (byte)((copy.Length - 6) / 256); copy[5] = (byte)((copy.Length - 6) % 256); copy[8] = (byte)buffer.Length; Array.Copy(buffer, 0, copy, 9, buffer.Length); break; } case 0x05: { // 写单个线圈 int address = data[8] * 256 + data[9]; if (data[10] == 0xFF && data[11] == 0x00) { WriteCoil((ushort)address, true); } else if (data[10] == 0x00 && data[11] == 0x00) { WriteCoil((ushort)address, false); } copy = new byte[12]; Array.Copy(data, 0, copy, 0, 12); copy[4] = 0x00; copy[5] = 0x06; break; } case 0x06: { // 写单个寄存器 ushort address = (ushort)(data[8] * 256 + data[9]); short ValueOld = ReadShortRegister(address); // 写入到寄存器 WriteRegister(address, data[10], data[11]); short ValueNew = ReadShortRegister(address); // 触发写入请求 OnRegisterBeforWrite(address, ValueOld, ValueNew); copy = new byte[12]; Array.Copy(data, 0, copy, 0, 12); copy[4] = 0x00; copy[5] = 0x06; break; } case 0x0F: { // 写多个线圈 int address = data[8] * 256 + data[9]; int length = data[10] * 256 + data[11]; byte[] buffer = new byte[data.Length - 13]; Array.Copy(data, 13, buffer, 0, buffer.Length); bool[] value = BasicFramework.SoftBasic.ByteToBoolArray(buffer, length); WriteCoil((ushort)address, value); copy = new byte[12]; Array.Copy(data, 0, copy, 0, 12); copy[4] = 0x00; copy[5] = 0x06; break; } case 0x10: { // 写多个寄存器 int address = data[8] * 256 + data[9]; int length = data[10] * 256 + data[11]; byte[] buffer = new byte[data.Length - 13]; // 为了使服务器的数据订阅更加的准确,决定将设计改为等待所有的数据写入完成后,再统一触发订阅,2018年3月4日 20:56:47 MonitorAddress[] addresses = new MonitorAddress[length]; for (int i = 0; i < length; i++) { if ((2 * i + 14) < data.Length) { short ValueOld = ReadShortRegister((ushort)(address + i)); WriteRegister((ushort)(address + i), data[2 * i + 13], data[2 * i + 14]); short ValueNew = ReadShortRegister((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); } copy = new byte[12]; Array.Copy(data, 0, copy, 0, 12); copy[4] = 0x00; copy[5] = 0x06; break; } default: { copy = new byte[9]; Array.Copy(data, 0, copy, 0, 8); copy[4] = 0x00; copy[5] = 0x03; copy[7] = (byte)(data[7] + 0x80); copy[8] = 0x01; // 不支持的功能码 break; } } } catch (Exception ex) { state.WorkSocket?.Close( ); state = null; LogNet?.WriteException(LogHeaderText, ex); return; } try { // 管他是什么,先开始数据接收 // state.WorkSocket?.Close(); state.WorkSocket.BeginReceive(state.HeadByte, 0, 6, SocketFlags.None, new AsyncCallback(ModbusHeadReveiveCallback), state); } catch (Exception ex) { state.WorkSocket?.Close(); state = null; LogNet?.WriteException(LogHeaderText, "Send exception:", ex); return; } // 回发数据,先获取发送锁 state.hybirdLock.Enter(); state.WorkSocket.BeginSend(copy, 0, size: copy.Length, socketFlags: SocketFlags.None, callback: new AsyncCallback(DataSendCallBack), state: state); // 通知处理消息 if (IsStarted) { OnDataReceived?.Invoke(data); } } }