using DotNetty.Buffers; using DotNetty.Codecs; using DotNetty.Handlers.Timeout; using DotNetty.Transport.Bootstrapping; using DotNetty.Transport.Channels; using DotNetty.Transport.Channels.Sockets; using JT808.DotNetty.Client.Handlers; using Microsoft.Extensions.Logging; using System; using System.Runtime.InteropServices; using Microsoft.Extensions.DependencyInjection; using System.Net; using JT808.DotNetty.Client.Metadata; using JT808.DotNetty.Client.Codecs; using JT808.DotNetty.Client.Services; using JT808.Protocol; using System.Threading.Tasks; namespace JT808.DotNetty.Client { public sealed class JT808TcpClient : IDisposable { private MultithreadEventLoopGroup group; private IChannel clientChannel; private bool disposed = false; public JT808DeviceConfig DeviceConfig { get; private set; } public ILoggerFactory LoggerFactory { get; private set; } public JT808TcpClient(JT808DeviceConfig deviceConfig, IServiceProvider serviceProvider) { DeviceConfig = deviceConfig; LoggerFactory = serviceProvider.GetRequiredService(); JT808SendAtomicCounterService jT808SendAtomicCounterService = serviceProvider.GetRequiredService(); JT808ReceiveAtomicCounterService jT808ReceiveAtomicCounterService = serviceProvider.GetRequiredService(); IJT808Config jT808Config = serviceProvider.GetRequiredService(); group = new MultithreadEventLoopGroup(1); Bootstrap bootstrap = new Bootstrap(); bootstrap.Group(group); bootstrap.Channel(); bootstrap .Option(ChannelOption.Allocator, new UnpooledByteBufferAllocator()) .Handler(new ActionChannelInitializer(channel => { channel.Pipeline.AddLast("jt808TcpBuffer", new DelimiterBasedFrameDecoder(65535, Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.BeginFlag }), Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.EndFlag }))); channel.Pipeline.AddLast("systemIdleState", new IdleStateHandler(60, deviceConfig.Heartbeat, 3600)); channel.Pipeline.AddLast("jt808TcpDecode", new JT808ClientTcpDecoder()); channel.Pipeline.AddLast("jt808TcpEncode", new JT808ClientTcpEncoder(jT808Config,jT808SendAtomicCounterService, LoggerFactory)); channel.Pipeline.AddLast("jt808TcpClientConnection", new JT808TcpClientConnectionHandler(this)); channel.Pipeline.AddLast("jt808TcpService", new JT808TcpClientHandler(jT808ReceiveAtomicCounterService,this)); })); Task.Run(async () => { clientChannel = await bootstrap.ConnectAsync(IPAddress.Parse(DeviceConfig.TcpHost), DeviceConfig.TcpPort); }); } public void Send(JT808ClientRequest request) { if (disposed) return; if (clientChannel == null) throw new NullReferenceException("Channel is empty."); if (request == null) throw new ArgumentNullException("JT808ClientRequest Parameter is empty."); if (clientChannel.Active && clientChannel.Open) { clientChannel.WriteAndFlushAsync(request); } } public bool IsOpen { get { if (clientChannel == null) return false; return clientChannel.Active && clientChannel.Open; } } private void Dispose(bool disposing) { if (disposed) { return; } if (disposing) { // 清理托管资源 group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)); } disposed = true; } ~JT808TcpClient() { //必须为false //这表明,隐式清理时,只要处理非托管资源就可以了。 Dispose(false); } public void Dispose() { //必须为true Dispose(true); //通知垃圾回收机制不再调用终结器(析构器) GC.SuppressFinalize(this); } } }