using DotNetty.Buffers; using DotNetty.Transport.Channels; using Newtonsoft.Json.Linq; using Serilog; using System.Collections; using System.Diagnostics; using System.Net; using System.Text; using Yunda.SOMS.OperationsMainSiteGatewayServer.TcpSocket.Models; using Yunda.SOMS.OperationsMainSiteGatewayServer.TcpSocket.TestData; namespace Yunda.SOMS.OperationsMainSiteGatewayServer.TcpSocket.Server { public class DotNettyServerHandler : SimpleChannelInboundHandler { // 定义设备信息类 private class DeviceInfo { public bool Status { get; set; } // 设备状态(运行或离线) public DateTime LastUpdate { get; set; } // 最后更新时间 public int OfflineCount { get; set; } // 连续离线计数 } private IChannelHandlerContext _context; // 定义事件,事件处理程序包含消息和功能描述 private readonly Dictionary _connections; private readonly Action _onMessageReceived; private readonly Action _onDeviceConnection; Dictionary _deviceRunStates = new Dictionary(); byte _serverAddr; public DotNettyServerHandler(Dictionary connections, Action onMessageReceived, Action> deviceBoardStatesAction, byte addr) { _serverAddr = addr; _connections = connections; _onMessageReceived = onMessageReceived; //_onDeviceConnection = onDeviceConnection; Task.Factory.StartNew(async () => { while (true) { try { CheckAndUpdateDeviceStates(); SendTestData(); await Task.Delay(1000); } catch (Exception ex) { //MonitoringEventBus.LogHandler($"客户端连接错误:{ex.StackTrace}", "定值错误信息"); } } }, TaskCreationOptions.LongRunning); } byte heartbeatDelayCount = 0; byte heartbeatCount = 0; async void CheckAndUpdateDeviceStates() { try { if (heartbeatDelayCount ==0) { await HandleHeartbeat(_context, _serverAddr, heartbeatCount); foreach (var entry in _deviceRunStates) { var deviceAddress = entry.Key; var date = entry.Value; // 检查是否超过10秒未更新 if ((DateTime.Now - date).TotalSeconds > 65) { Log.Warning($"[{DateTime.Now}] {deviceAddress} 判定为离线(超过65秒未更新)"); await _context.CloseAsync(); _connections.Remove(deviceAddress); } } } else { heartbeatDelayCount++; } if (heartbeatDelayCount == 30) { heartbeatDelayCount = 0; } } catch (Exception ex) { Log.Error(ex,$"状态检测"); } } int sequence = 31; void SendTestData() { var data = SimulateData.SendProductionInformation(); // 创建一个应用控制字实例 ApplicationControlWord controlWord = new ApplicationControlWord(fir: true, fin: true, con: true, sequence: sequence); // 将控制字转换为字节 byte controlByte = controlWord.ToByte(); Log.Information($"Control Byte: 0x{controlByte:X2}"); // 输出控制字的十六进制表示 SendCustomMessageAsync(_context, _serverAddr, controlByte, 1,data); sequence--; if (sequence == 15) { sequence = 31; } } public async override void ChannelActive(IChannelHandlerContext context) { try { string clientIp = context.Channel.RemoteAddress.ToString(); Log.Information($"客户端连接:{clientIp}", "103客户端发送消息"); await HandleHeartbeat(context, _serverAddr, heartbeatCount); base.ChannelActive(context); } catch (Exception ex) { Log.Information($"{ex.StackTrace}", "103客户端错误信息"); } } public override void ChannelInactive(IChannelHandlerContext context) { try { string clientIp = context.Channel.RemoteAddress.ToString(); Log.Information($"客户端断开连接:{clientIp}", "103客户端发送消息"); base.ChannelInactive(context); } catch (Exception ex) { Log.Information($"{ex.StackTrace}", "103客户端错误信息"); } } protected async override void ChannelRead0(IChannelHandlerContext ctx, IByteBuffer msg) { _context = ctx; try { byte startByte = msg.ReadByte(); ushort length = msg.ReadUnsignedShort(); byte address = msg.ReadByte(); if (length == 6) //心跳 { HandleHeatbeatInfo(msg, address, ctx); return; } byte controlWord = msg.ReadByte(); byte functionType = msg.ReadByte(); // 计算数据长度 int dataLength = length - 6; if (msg.ReadableBytes < dataLength) { // 数据不足,等待更多数据 return; } byte[] data = new byte[dataLength]; msg.ReadBytes(data); string clientIp = ctx.Channel.RemoteAddress.ToString(); Log.Information($"客户端ip地址:{clientIp}"); string description = FunctionCodeDescriptions.GetDescription(functionType); Log.Information($"地址 {address} 功能码:{functionType} 数据长度:{dataLength}", "103客户端消息"); Log.Information($"地址 {address} 功能码:{functionType} 数据长度:{dataLength}", "103客户端消息"); Task.Run(() => _onMessageReceived?.Invoke(address, data, functionType)); HandleFunctionCodeAsync(functionType, address, controlWord, data, ctx); } catch (Exception ex) { Log.Information($"Error in ChannelRead0: {ex.StackTrace}", "103客户端发送消息"); } } private void HandleHeatbeatInfo(IByteBuffer msg, byte address, IChannelHandlerContext ctx) { byte handleHearfunctionType = msg.ReadByte(); byte handleHeardata = msg.ReadByte(); if (handleHearfunctionType == 7) { if (_connections.ContainsKey(address)) { _connections[address] = ctx; } else { _connections.Add(address, ctx); } Log.Information($"接受到心跳信息:地址:{address} 序列号:{handleHeardata}"); if (_deviceRunStates.ContainsKey(address)) { _deviceRunStates[address] = DateTime.Now; } else { _deviceRunStates.Add(address, DateTime.Now); } //await HandleHeartbeat(ctx, _serverAddr, handleHeardata); } } private async Task HandleFunctionCodeAsync(byte functionType, byte address, byte controlWord, byte[] data, IChannelHandlerContext ctx) { switch (functionType) { case 0: break; case 1: //装置生产信息报文 Log.Information($"收到装置生产信息报文: {BitConverter.ToString(data)}"); break; case 2: // 装置版本信息报文 break; case 3: //装置运行信息报文 Log.Information($"版本信息: {Encoding.ASCII.GetString(data)}", "103客户端信息"); break; case 4: // 板件状态自诊断信息报文 break; case 5: //装置运行状态自诊断信息报文 //MonitoringEventBus.LogHandler($"开入开出信息: {Encoding.ASCII.GetString(data)}", "103客户端信息"); break; case 6: //二次回路智能诊断信息报文 //await UpdateDeviceCommunicationStateAsync(address, data, ctx); break; case 10: // 信息召唤 Log.Information("信息召唤"); break; default: //MonitoringEventBus.LogHandler("未知的功能码", "103客户端信息"); break; } } /// /// 心跳信息 /// /// /// /// /// private async Task HandleHeartbeat(IChannelHandlerContext context, byte address, byte data) { if (context == null) { return; } try { // 构建数据帧 byte[] buffer = new byte[6]; // 填入启动字符 buffer[0] = 0x68; // 填入长度(假设数据部分为50字节,2字节长度字段+1字节地址+1字节标志位) byte dataLength = 6; buffer[1] = 0; // 长度低字节 buffer[2] = dataLength; // 长度高字节 // 填入地址、应用控制字、功能类型 buffer[3] = address; // 示例地址 buffer[4] = 7; // 示例功能类型 buffer[5] = data; // 填入数据部分 IByteBuffer wrappedBuffer = Unpooled.WrappedBuffer(buffer); // 发送数据 await context.WriteAndFlushAsync(wrappedBuffer); Log.Information($"发送心跳信息:序号:{data} 地址:{address}"); } catch (Exception ex) { Log.Error(ex, "心跳信息"); } heartbeatCount++; // 防止溢出 if (heartbeatCount == 0xFF) // 如果超过 255,则重置为 0 { heartbeatCount = 0; } } public override async void ExceptionCaught(IChannelHandlerContext context, Exception ex) { try { //MonitoringEventBus.LogHandler(ex.Message, "103客户端错误消息"); Log.Information(ex, "错误消息"); await context.CloseAsync(); } catch (Exception ex1) { //MonitoringEventBus.LogHandler($"Error: {ex1.StackTrace}", "关闭tcp客户端"); } } // 发送自定义消息 public async Task SendCustomByteMessageAsync(IChannelHandlerContext context, byte address, byte controlWord, byte functionType, byte data) { try { await SendCustomMessageAsync(context, address, controlWord, functionType, new byte[] { data }); } catch (Exception ex) { Log.Information($"Error: {ex.StackTrace}"); } } // 发送自定义消息 public async Task SendCustomMessageAsync(IChannelHandlerContext context, byte address, byte controlWord, byte functionType, byte[] data) { try { if (context==null|| data == null|| data.Length==0) { return; } ushort dataLength = (ushort)(6 + data.Length); // 构建数据帧 byte[] buffer = new byte[dataLength]; // 填入启动字符 buffer[0] = 0x68; // 填入长度(假设数据部分为50字节,2字节长度字段+1字节地址+1字节标志位) byte[] bytes = BitConverter.GetBytes(dataLength); buffer[1] = bytes[0]; // 长度低字节 buffer[2] = bytes[1]; // 长度高字节 // 填入地址、应用控制字、功能类型 buffer[3] = address; // 示例地址 buffer[4] = controlWord; // 示例应用控制字 buffer[5] = functionType; // 示例功能类型 for (ushort i = 6; i < dataLength; i++) { buffer[i] = data[i-6]; } // 填入数据部分 IByteBuffer wrappedBuffer = Unpooled.WrappedBuffer(buffer); // 发送数据 await context.WriteAndFlushAsync(wrappedBuffer); string hexString = BitConverter.ToString(buffer).Replace("-", " "); Log.Information($"地址:{address} 功能码:{functionType} 数据:{hexString}"); await Task.Delay(100); } catch (Exception ex) { Log.Information($"Error: {ex.StackTrace}"); } } } }