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 { /// /// TCP客户端引擎 /// public class TcpClientEngine { private Bootstrap SocketBootstrap = new(); private MultithreadEventLoopGroup WorkGroup = new(); private IChannel channel; /// /// 初始化 TCP 客户端编解码管道并启动后台连接监视。 /// /// 服务端地址、端口及协议编解码配置。 public async Task InitEngine(TcpEngineInitParam tcpEngineInitParam) { LogHelper.Info("正在启动TCP客户端引擎-----------"); SocketBootstrap .Group(WorkGroup) .Channel() .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(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); } }); } } }