101 lines
4.1 KiB
C#
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);
|
|
}
|
|
|
|
});
|
|
|
|
|
|
}
|
|
}
|
|
}
|