Files
2026-09-02 16:31:50 +08:00

101 lines
4.1 KiB
C#

using DotNetty.Buffers;
using DotNetty.Codecs;
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using DotNetty.Transport.Channels.Sockets;
using JSMachine.WMS.Infrastructure.Helper;
using JSMachine.WMS.Netty.Common.Model;
using System;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace JSMachine.WMS.Netty.NettyAsClient
{
/// <summary>
/// TCP客户端引擎
/// </summary>
public class TcpClientEngine
{
private Bootstrap SocketBootstrap = new();
private MultithreadEventLoopGroup WorkGroup = new();
private IChannel channel;
/// <summary>
/// 初始化 TCP 客户端编解码管道并启动后台连接监视。
/// </summary>
/// <param name="tcpEngineInitParam">服务端地址、端口及协议编解码配置。</param>
public async Task InitEngine(TcpEngineInitParam tcpEngineInitParam)
{
LogHelper.Info("正在启动TCP客户端引擎-----------");
SocketBootstrap
.Group(WorkGroup)
.Channel<TcpSocketChannel>()
.Option(ChannelOption.TcpNodelay, true)
.Option(ChannelOption.ConnectTimeout, TimeSpan.FromSeconds(2))
.Option(ChannelOption.SoKeepalive, true)
//以下两种方式都是设置一次性能接收的数据包大小
//.Option(ChannelOption.SoRcvbuf, 4 * 1024)
.Option(ChannelOption.RcvbufAllocator, new FixedRecvByteBufAllocator(25))
.Handler(new ActionChannelInitializer<ISocketChannel>(channel =>
{
IChannelPipeline pipeline = channel.Pipeline;
if (!string.IsNullOrEmpty(tcpEngineInitParam.DecoderWord))
{
IByteBuffer delimiter = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("\r"));
//简单的协议可以直接使用自带的分隔符解码器
pipeline.AddLast("framing-dec", new DelimiterBasedFrameDecoder(32, true, delimiter));
}
else
{
//pipeline.AddLast("framing-enc", new LengthFieldPrepender(2));
pipeline.AddLast("framing-dec", new LengthFieldBasedFrameDecoder(ushort.MaxValue, 0, 2, 0, 2));
}
if (!string.IsNullOrEmpty(tcpEngineInitParam.EncoderWord))
{
//自定义编码器,编解码器必须写在处理器之前,否则数据包将不会经过编解码器
pipeline.AddLast(new JSMachine.WMS.Netty.NettyAsClient.Codec.Encoder(tcpEngineInitParam.EncoderWord));
}
else
{
pipeline.AddLast(new JSMachine.WMS.Netty.NettyAsClient.Codec.EnCoderPrint(tcpEngineInitParam.EncoderWord));
}
pipeline.AddLast("echo", new EchoClientChannelHandler(tcpEngineInitParam));
}));
await MonitorTcpConnection(tcpEngineInitParam.IP, tcpEngineInitParam.Port);
}
private async Task MonitorTcpConnection(string serverIP, int port)
{
// 连接断开后持续重试,保证扫码设备临时掉线时能够自动恢复通信。
await Task.Run(async () =>
{
while (true)
{
if (channel == null || !channel.Active)
{
try
{
channel = await SocketBootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(serverIP), port));
}
catch (Exception ex)
{
LogHelper.Error($"连接服务端 {serverIP} 失败,错误信息 {ex.Message} 即将重新连接");
}
}
Thread.Sleep(5000);
}
});
}
}
}