using Abp.Dependency; using DotNetty.Buffers; using DotNetty.Codecs; using DotNetty.Transport.Bootstrapping; using DotNetty.Transport.Channels; using DotNetty.Transport.Channels.Sockets; using Serilog; using System.Diagnostics; using System.Runtime; namespace Yunda.SOMS.OperationsMainSiteGatewayServer.TcpSocket.Server { public class DotNettyTcpServer : ISingletonDependency { private readonly Dictionary connections = new Dictionary(); // 定义 MessageReceived 事件 public event Action< byte, byte[], byte> MessageReceived; // 装置地址,功能码,消息 public event Action> deviceBoardStatesAction; public DotNettyTcpServer() { //_dotNettyServerHandler = dotNettyServerHandler; } MultithreadEventLoopGroup bossGroup ; MultithreadEventLoopGroup workerGroup ; int maxFrameLength = 65536; // 设置最大帧长度 int lengthFieldOffset = 1; // 长度字段的偏移量,从启动字符之后开始 int lengthFieldLength = 2; // 长度字段的字节长度 int lengthAdjustment = -3; // 长度调整,将读取的长度减去启动字符和长度字段的字节数 int initialBytesToStrip = 0; // 保留所有字节 public async Task RunServerAsync(byte addr) { bossGroup = new MultithreadEventLoopGroup(1); workerGroup = new MultithreadEventLoopGroup(); try { GCSettings.LatencyMode = GCLatencyMode.LowLatency; var bootstrap = new ServerBootstrap(); bootstrap.Group(bossGroup, workerGroup) .Channel() .Option(ChannelOption.SoBacklog, 100) .ChildHandler(new ActionChannelInitializer(channel => { channel.Pipeline.AddLast(new LengthFieldBasedFrameDecoder( maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip )); channel.Pipeline.AddLast(new DotNettyServerHandler(connections, MessageReceived, deviceBoardStatesAction,addr)); channel.Pipeline.AddLast("hexDumpHandler", new HexDumpHandler()); })); IChannel boundChannel = await bootstrap.BindAsync(3000); Log.Information("服务器启动并监听端口 3000..."); } finally { } } public async Task StopSeverAsync() { try { await Task.WhenAll( bossGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)), workerGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1))); } catch (Exception ex) { Log.Information("服务器关闭并监听端口 7110...", "获取信息"); } } public async void SendMessageByIp(byte address, byte controlWord, byte functionCode , byte message) { if (connections.TryGetValue(address, out IChannelHandlerContext context)) { try { //var buffer = Unpooled.WrappedBuffer(System.Text.Encoding.UTF8.GetBytes(message)); //context.WriteAndFlushAsync(buffer); // 构建数据帧 byte[] buffer = new byte[7]; // 填入启动字符 buffer[0] = 0x16; // 填入长度(假设数据部分为50字节,2字节长度字段+1字节地址+1字节标志位) byte dataLength = 7; buffer[1] = 0; // 长度低字节 buffer[2] = dataLength; // 长度高字节 // 填入地址、应用控制字、功能类型 buffer[3] = address; // 示例地址 buffer[4] = controlWord; // 示例应用控制字 buffer[5] = functionCode; // 示例功能类型 buffer[6] = message; // 填入数据部分 IByteBuffer wrappedBuffer = Unpooled.WrappedBuffer(buffer); // 发送数据 await context.WriteAndFlushAsync(wrappedBuffer); //Debug.WriteLine($"发送消息到 装置:{address}: {message}"); string hexString = BitConverter.ToString(buffer); //MonitoringEventBus.LogHandler($"地址:{address} 功能码:{functionCode} 数据:{hexString}", "103客户端发送消息"); } catch (Exception ex) { Debug.WriteLine(ex.ToString() ); } } else { Debug.WriteLine($"未找到 装置 为 {address} 的连接"); } } // 断开指定 IP 地址的连接 public void DisconnectByIp(byte addr) { if (connections.TryGetValue(addr, out IChannelHandlerContext context)) { context.CloseAsync(); // 关闭连接 connections.Remove(addr); // 从字典中移除该连接 Debug.WriteLine($"断开 地址 为 {addr} 的连接"); } else { Debug.WriteLine($"未找到 地址 为 {addr} 的连接"); } } } }