using DotNetty.Buffers; using DotNetty.Codecs; using DotNetty.Handlers.Timeout; using DotNetty.Transport.Bootstrapping; using DotNetty.Transport.Channels; using DotNetty.Transport.Libuv; using JT809.DotNetty.Core.Configurations; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System; using System.Net; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using JT809.Protocol; using JT809.DotNetty.Core.Codecs; using JT809.DotNetty.Core.Handlers; namespace JT809.DotNetty.Core.Services { /// /// JT809 Tcp网关服务 /// internal class JT809MainServerHost : IHostedService { private readonly IServiceProvider serviceProvider; private readonly JT809Configuration configuration; private readonly ILogger logger; private DispatcherEventLoopGroup bossGroup; private WorkerEventLoopGroup workerGroup; private IChannel bootstrapChannel; private IByteBufferAllocator serverBufferAllocator; private ILoggerFactory loggerFactory; public JT809MainServerHost( IServiceProvider provider, ILoggerFactory loggerFactory, IOptions jT809ConfigurationAccessor) { serviceProvider = provider; configuration = jT809ConfigurationAccessor.Value; logger = loggerFactory.CreateLogger(); this.loggerFactory = loggerFactory; } public Task StartAsync(CancellationToken cancellationToken) { bossGroup = new DispatcherEventLoopGroup(); workerGroup = new WorkerEventLoopGroup(bossGroup, configuration.EventLoopCount); serverBufferAllocator = new PooledByteBufferAllocator(); ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.Group(bossGroup, workerGroup); bootstrap.Channel(); if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { bootstrap .Option(ChannelOption.SoReuseport, true) .ChildOption(ChannelOption.SoReuseaddr, true); } bootstrap .Option(ChannelOption.SoBacklog, configuration.SoBacklog) .ChildOption(ChannelOption.Allocator, serverBufferAllocator) .ChildHandler(new ActionChannelInitializer(channel => { IChannelPipeline pipeline = channel.Pipeline; channel.Pipeline.AddLast("jt809MainBuffer", new DelimiterBasedFrameDecoder(int.MaxValue, Unpooled.CopiedBuffer(new byte[] { JT809Package.BEGINFLAG }), Unpooled.CopiedBuffer(new byte[] { JT809Package.ENDFLAG }))); channel.Pipeline.AddLast("jt809MainSystemIdleState", new IdleStateHandler( configuration.ReaderIdleTimeSeconds, configuration.WriterIdleTimeSeconds, configuration.AllIdleTimeSeconds)); pipeline.AddLast("jt809MainEncode", new JT809Encoder()); pipeline.AddLast("jt809MainDecode", new JT809Decoder()); channel.Pipeline.AddLast("jt809MainConnection", new JT809MainServerConnectionHandler(loggerFactory)); using (var scope = serviceProvider.CreateScope()) { channel.Pipeline.AddLast("jt809MainService", scope.ServiceProvider.GetRequiredService()); } })); logger.LogInformation($"JT809 TCP Server start at {IPAddress.Any}:{configuration.TcpPort}."); return bootstrap.BindAsync(configuration.TcpPort) .ContinueWith(i => bootstrapChannel = i.Result); } public async Task StopAsync(CancellationToken cancellationToken) { await bootstrapChannel.CloseAsync(); var quietPeriod = configuration.QuietPeriodTimeSpan; var shutdownTimeout = configuration.ShutdownTimeoutTimeSpan; await workerGroup.ShutdownGracefullyAsync(quietPeriod, shutdownTimeout); await bossGroup.ShutdownGracefullyAsync(quietPeriod, shutdownTimeout); } } }