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} 的连接");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|