2024-11-26 13:45:28 +08:00

141 lines
5.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<byte, IChannelHandlerContext> connections = new Dictionary<byte, IChannelHandlerContext>();
// 定义 MessageReceived 事件
public event Action< byte, byte[], byte> MessageReceived; // 装置地址,功能码,消息
public event Action<Dictionary<byte, int[]>> 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<TcpServerSocketChannel>()
.Option(ChannelOption.SoBacklog, 100)
.ChildHandler(new ActionChannelInitializer<IChannel>(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} 的连接");
}
}
}
}