141 lines
5.8 KiB
C#
141 lines
5.8 KiB
C#
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} 的连接");
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|