@@ -0,0 +1,33 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.DotNetty.Abstractions.Dtos | |||
{ | |||
public class JT809SystemCollectInfoDto | |||
{ | |||
/// <summary> | |||
/// 进程Id | |||
/// </summary> | |||
public int ProcessId { get; set; } | |||
/// <summary> | |||
/// 进程分配内存 | |||
/// 单位MB | |||
/// </summary> | |||
public double WorkingSet64 { get; set; } | |||
/// <summary> | |||
/// 进程分配内存峰值 | |||
/// 单位MB | |||
/// </summary> | |||
public double PeakWorkingSet64 { get; set; } | |||
/// <summary> | |||
/// 进程分配私有内存 | |||
/// 单位MB | |||
/// </summary> | |||
public double PrivateMemorySize64 { get; set; } | |||
/// <summary> | |||
/// 进程执行CPU总处理时间 | |||
/// </summary> | |||
public TimeSpan CPUTotalProcessorTime { get; set; } | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
using System.Threading.Tasks; | |||
namespace JT809.DotNetty.Abstractions | |||
{ | |||
/// <summary> | |||
/// 会话通知(在线/离线) | |||
/// </summary> | |||
public interface IJT809SessionPublishing | |||
{ | |||
Task PublishAsync(string topicName, string value); | |||
} | |||
} |
@@ -0,0 +1,7 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<PropertyGroup> | |||
<TargetFramework>netstandard2.0</TargetFramework> | |||
</PropertyGroup> | |||
</Project> |
@@ -0,0 +1,25 @@ | |||
namespace JT809.DotNetty.Abstractions | |||
{ | |||
public static class JT809Constants | |||
{ | |||
public const string SessionOnline= "JT809SessionOnline"; | |||
public const string SessionOffline = "JT809SessionOffline"; | |||
public static class JT809WebApiRouteTable | |||
{ | |||
public const string RouteTablePrefix = "/jt809api"; | |||
public const string SessionPrefix = "Session"; | |||
public const string SystemCollectPrefix = "SystemCollect"; | |||
public const string TcpPrefix = "Tcp"; | |||
/// <summary> | |||
///获取当前系统进程使用率 | |||
/// </summary> | |||
public static string SystemCollectGet = $"{RouteTablePrefix}/{SystemCollectPrefix}/Get"; | |||
} | |||
} | |||
} |
@@ -0,0 +1,20 @@ | |||
using DotNetty.Buffers; | |||
using DotNetty.Codecs; | |||
using System.Collections.Generic; | |||
using DotNetty.Transport.Channels; | |||
using JT809.Protocol; | |||
namespace JT809.DotNetty.Core.Codecs | |||
{ | |||
public class JT809TcpDecoder : ByteToMessageDecoder | |||
{ | |||
protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List<object> output) | |||
{ | |||
byte[] buffer = new byte[input.Capacity + 2]; | |||
input.ReadBytes(buffer, 1, input.Capacity); | |||
buffer[0] = JT809Package.BEGINFLAG; | |||
buffer[input.Capacity + 1] = JT809Package.ENDFLAG; | |||
output.Add(buffer); | |||
} | |||
} | |||
} |
@@ -0,0 +1,31 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Text; | |||
namespace JT809.DotNetty.Core.Configurations | |||
{ | |||
public class JT809ClientConfiguration | |||
{ | |||
public string Host { get; set; } | |||
public int Port { get; set; } | |||
private EndPoint endPoint; | |||
public EndPoint EndPoint | |||
{ | |||
get | |||
{ | |||
if (endPoint == null) | |||
{ | |||
if (IPAddress.TryParse(Host, out IPAddress ip)) | |||
{ | |||
endPoint = new IPEndPoint(ip, Port); | |||
} | |||
} | |||
return endPoint; | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,29 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.DotNetty.Core.Configurations | |||
{ | |||
public class JT809Configuration | |||
{ | |||
public int TcpPort { get; set; } = 809; | |||
public int QuietPeriodSeconds { get; set; } = 1; | |||
public TimeSpan QuietPeriodTimeSpan => TimeSpan.FromSeconds(QuietPeriodSeconds); | |||
public int ShutdownTimeoutSeconds { get; set; } = 3; | |||
public TimeSpan ShutdownTimeoutTimeSpan => TimeSpan.FromSeconds(ShutdownTimeoutSeconds); | |||
public int SoBacklog { get; set; } = 8192; | |||
public int EventLoopCount { get; set; } = Environment.ProcessorCount; | |||
public int ReaderIdleTimeSeconds { get; set; } = 180; | |||
public int WriterIdleTimeSeconds { get; set; } = 60; | |||
public int AllIdleTimeSeconds { get; set; } = 180; | |||
} | |||
} |
@@ -0,0 +1,26 @@ | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Text; | |||
namespace JT809.DotNetty.Core.Converters | |||
{ | |||
public class JsonIPAddressConverter : JsonConverter | |||
{ | |||
public override bool CanConvert(Type objectType) | |||
{ | |||
return (objectType == typeof(IPAddress)); | |||
} | |||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) | |||
{ | |||
writer.WriteValue(value.ToString()); | |||
} | |||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) | |||
{ | |||
return IPAddress.Parse((string)reader.Value); | |||
} | |||
} | |||
} |
@@ -0,0 +1,32 @@ | |||
using Newtonsoft.Json; | |||
using Newtonsoft.Json.Linq; | |||
using System; | |||
using System.Net; | |||
namespace JT809.DotNetty.Core.Converters | |||
{ | |||
public class JsonIPEndPointConverter: JsonConverter | |||
{ | |||
public override bool CanConvert(Type objectType) | |||
{ | |||
return (objectType == typeof(IPEndPoint)); | |||
} | |||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) | |||
{ | |||
IPEndPoint ep = (IPEndPoint)value; | |||
JObject jo = new JObject(); | |||
jo.Add("Host", JToken.FromObject(ep.Address, serializer)); | |||
jo.Add("Port", ep.Port); | |||
jo.WriteTo(writer); | |||
} | |||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) | |||
{ | |||
JObject jo = JObject.Load(reader); | |||
IPAddress address = jo["Host"].ToObject<IPAddress>(serializer); | |||
int port = (int)jo["Port"]; | |||
return new IPEndPoint(address, port); | |||
} | |||
} | |||
} |
@@ -0,0 +1,109 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using JT809.DotNetty.Core.Interfaces; | |||
using JT809.DotNetty.Core.Metadata; | |||
using JT809.Protocol.Enums; | |||
using JT809.Protocol.Extensions; | |||
using JT809.Protocol.MessageBody; | |||
namespace JT809.DotNetty.Core.Handlers | |||
{ | |||
/// <summary> | |||
/// 基于Tcp模式抽象消息处理业务 | |||
/// 自定义消息处理业务 | |||
/// 注意: | |||
/// 1.ConfigureServices: | |||
/// services.Replace(new ServiceDescriptor(typeof(JT809MsgIdTcpHandlerBase),typeof(JT809MsgIdCustomTcpHandlerImpl),ServiceLifetime.Singleton)); | |||
/// 2.解析具体的消息体,具体消息调用具体的JT809Serializer.Deserialize<T> | |||
/// </summary> | |||
public abstract class JT809MsgIdTcpHandlerBase | |||
{ | |||
protected JT809TcpSessionManager sessionManager { get; } | |||
protected IVerifyCodeGenerator verifyCodeGenerator { get; } | |||
/// <summary> | |||
/// 初始化消息处理业务 | |||
/// </summary> | |||
protected JT809MsgIdTcpHandlerBase( | |||
IVerifyCodeGenerator verifyCodeGenerator, | |||
JT809TcpSessionManager sessionManager) | |||
{ | |||
this.sessionManager = sessionManager; | |||
this.verifyCodeGenerator = verifyCodeGenerator; | |||
HandlerDict = new Dictionary<JT809BusinessType, Func<JT809Request, JT809Response>> | |||
{ | |||
{JT809BusinessType.主链路登录请求消息, Msg0x1001}, | |||
{JT809BusinessType.主链路注销请求消息, Msg0x1003}, | |||
{JT809BusinessType.主链路连接保持请求消息, Msg0x1005}, | |||
{JT809BusinessType.主链路动态信息交换消息, Msg0x1200} | |||
}; | |||
//SubHandlerDict = new Dictionary<JT809SubBusinessType, Func<JT809Request, JT809Response>> | |||
//{ | |||
// {JT809SubBusinessType.实时上传车辆定位信息, Msg0x1200_0x1202}, | |||
//}; | |||
} | |||
public Dictionary<JT809BusinessType, Func<JT809Request, JT809Response>> HandlerDict { get; protected set; } | |||
//public Dictionary<JT809SubBusinessType, Func<JT809Request, JT809Response>> SubHandlerDict { get; protected set; } | |||
/// <summary> | |||
/// 主链路登录应答消息 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public virtual JT809Response Msg0x1001(JT809Request request) | |||
{ | |||
var package= JT809BusinessType.主链路登录应答消息.Create(new JT809_0x1002() | |||
{ | |||
Result= JT809_0x1002_Result.成功, | |||
VerifyCode= verifyCodeGenerator.Create() | |||
}); | |||
return new JT809Response(package,100); | |||
} | |||
/// <summary> | |||
/// 主链路注销应答消息 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public virtual JT809Response Msg0x1003(JT809Request request) | |||
{ | |||
var package = JT809BusinessType.主链路注销应答消息.Create(); | |||
return new JT809Response(package, 100); | |||
} | |||
/// <summary> | |||
/// 主链路连接保持应答消息 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public virtual JT809Response Msg0x1005(JT809Request request) | |||
{ | |||
var package = JT809BusinessType.主链路连接保持应答消息.Create(); | |||
return new JT809Response(package, 100); | |||
} | |||
/// <summary> | |||
/// 主链路动态信息交换消息 | |||
/// </summary> | |||
/// <param name="request"></param> | |||
/// <returns></returns> | |||
public virtual JT809Response Msg0x1200(JT809Request request) | |||
{ | |||
return null; | |||
} | |||
///// <summary> | |||
///// 主链路动态信息交换消息 | |||
///// </summary> | |||
///// <param name="request"></param> | |||
///// <returns></returns> | |||
//public virtual JT809Response Msg0x1200_0x1202(JT809Request request) | |||
//{ | |||
// return null; | |||
//} | |||
} | |||
} |
@@ -0,0 +1,14 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.DotNetty.Core.Interfaces | |||
{ | |||
/// <summary> | |||
/// 校验码生成器 | |||
/// </summary> | |||
public interface IVerifyCodeGenerator | |||
{ | |||
uint Create(); | |||
} | |||
} |
@@ -0,0 +1,13 @@ | |||
using JT809.DotNetty.Abstractions; | |||
using System.Threading.Tasks; | |||
namespace JT809.DotNetty.Core | |||
{ | |||
internal class JT809SessionPublishingEmptyImpl : IJT809SessionPublishing | |||
{ | |||
public Task PublishAsync(string topicName, string value) | |||
{ | |||
return Task.CompletedTask; | |||
} | |||
} | |||
} |
@@ -0,0 +1,15 @@ | |||
using JT809.DotNetty.Core.Interfaces; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.DotNetty.Core.Internal | |||
{ | |||
internal class VerifyCodeGeneratorDefaultImpl : IVerifyCodeGenerator | |||
{ | |||
public uint Create() | |||
{ | |||
return (uint)Guid.NewGuid().GetHashCode(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,23 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<PropertyGroup> | |||
<TargetFramework>netstandard2.0</TargetFramework> | |||
<LangVersion>7.1</LangVersion> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<PackageReference Include="DotNetty.Handlers" Version="0.6.0" /> | |||
<PackageReference Include="DotNetty.Transport.Libuv" Version="0.6.0" /> | |||
<PackageReference Include="DotNetty.Codecs" Version="0.6.0" /> | |||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="2.2.0" /> | |||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.2.0" /> | |||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" /> | |||
<PackageReference Include="Microsoft.Extensions.Options" Version="2.2.0" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\JT809.DotNetty.Abstractions\JT809.DotNetty.Abstractions.csproj" /> | |||
<ProjectReference Include="..\JT809.Protocol\src\JT809.Protocol\JT809.Protocol.csproj" /> | |||
</ItemGroup> | |||
</Project> |
@@ -0,0 +1,59 @@ | |||
using JT809.DotNetty.Abstractions; | |||
using JT809.DotNetty.Core.Configurations; | |||
using JT809.DotNetty.Core.Converters; | |||
using JT809.DotNetty.Core.Interfaces; | |||
using JT809.DotNetty.Core.Internal; | |||
using JT809.DotNetty.Core.Services; | |||
using Microsoft.Extensions.Configuration; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.DependencyInjection.Extensions; | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Runtime.CompilerServices; | |||
[assembly: InternalsVisibleTo("JT809.DotNetty.Core.Test")] | |||
[assembly: InternalsVisibleTo("JT809.DotNetty.Tcp.Test")] | |||
[assembly: InternalsVisibleTo("JT809.DotNetty.Udp.Test")] | |||
[assembly: InternalsVisibleTo("JT809.DotNetty.WebApi.Test")] | |||
namespace JT809.DotNetty.Core | |||
{ | |||
public static class JT809CoreDotnettyExtensions | |||
{ | |||
static JT809CoreDotnettyExtensions() | |||
{ | |||
JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() => | |||
{ | |||
Newtonsoft.Json.JsonSerializerSettings settings = new Newtonsoft.Json.JsonSerializerSettings(); | |||
//日期类型默认格式化处理 | |||
settings.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat; | |||
settings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; | |||
//空值处理 | |||
settings.NullValueHandling = NullValueHandling.Ignore; | |||
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; | |||
settings.Converters.Add(new JsonIPAddressConverter()); | |||
settings.Converters.Add(new JsonIPEndPointConverter()); | |||
return settings; | |||
}); | |||
} | |||
public static IServiceCollection AddJT809Core(this IServiceCollection serviceDescriptors, IConfiguration configuration, Newtonsoft.Json.JsonSerializerSettings settings=null) | |||
{ | |||
if (settings != null) | |||
{ | |||
JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() => | |||
{ | |||
settings.Converters.Add(new JsonIPAddressConverter()); | |||
settings.Converters.Add(new JsonIPEndPointConverter()); | |||
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; | |||
return settings; | |||
}); | |||
} | |||
serviceDescriptors.Configure<JT809Configuration>(configuration.GetSection("JT809Configuration")); | |||
serviceDescriptors.TryAddSingleton<IVerifyCodeGenerator, VerifyCodeGeneratorDefaultImpl>(); | |||
serviceDescriptors.TryAddSingleton<IJT809SessionPublishing, JT809SessionPublishingEmptyImpl>(); | |||
serviceDescriptors.TryAddSingleton<JT809SimpleSystemCollectService>(); | |||
return serviceDescriptors; | |||
} | |||
} | |||
} |
@@ -0,0 +1,113 @@ | |||
using DotNetty.Buffers; | |||
using DotNetty.Codecs; | |||
using DotNetty.Handlers.Timeout; | |||
using DotNetty.Transport.Bootstrapping; | |||
using DotNetty.Transport.Channels; | |||
using DotNetty.Transport.Channels.Sockets; | |||
using JT809.DotNetty.Core.Codecs; | |||
using JT809.Protocol; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.Logging; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Net; | |||
using System.Text; | |||
namespace JT809.DotNetty.Core.Links | |||
{ | |||
/// <summary> | |||
/// 从链路客户端 | |||
/// </summary> | |||
public sealed class SubordinateLinkClient:IDisposable | |||
{ | |||
private Bootstrap bootstrap; | |||
private MultithreadEventLoopGroup group; | |||
private IChannel channel; | |||
private readonly ILogger<SubordinateLinkClient> logger; | |||
private readonly ILoggerFactory loggerFactory; | |||
private readonly IServiceProvider serviceProvider; | |||
private bool disposed = false; | |||
public SubordinateLinkClient( | |||
IServiceProvider provider, | |||
ILoggerFactory loggerFactory) | |||
{ | |||
this.serviceProvider = provider; | |||
this.loggerFactory = loggerFactory; | |||
this.logger = loggerFactory.CreateLogger<SubordinateLinkClient>(); | |||
} | |||
public async void ConnectAsync(string ip,int port,uint verifyCode) | |||
{ | |||
group = new MultithreadEventLoopGroup(); | |||
bootstrap = new Bootstrap(); | |||
bootstrap.Group(group) | |||
.Channel<TcpSocketChannel>() | |||
.Option(ChannelOption.TcpNodelay, true) | |||
.Handler(new ActionChannelInitializer<ISocketChannel>(channel => | |||
{ | |||
IChannelPipeline pipeline = channel.Pipeline; | |||
//下级平台1分钟发送心跳 | |||
//上级平台是3分钟没有发送就断开连接 | |||
channel.Pipeline.AddLast("jt809SystemIdleState", new IdleStateHandler(60,180,200)); | |||
//pipeline.AddLast(new ClientConnectionHandler(bootstrap, channeldic, loggerFactory)); | |||
channel.Pipeline.AddLast("jt809TcpBuffer", new DelimiterBasedFrameDecoder(int.MaxValue, | |||
Unpooled.CopiedBuffer(new byte[] { JT809Package.BEGINFLAG }), | |||
Unpooled.CopiedBuffer(new byte[] { JT809Package.ENDFLAG }))); | |||
using (var scope = serviceProvider.CreateScope()) | |||
{ | |||
channel.Pipeline.AddLast("jt809TcpDecode", scope.ServiceProvider.GetRequiredService<JT809TcpDecoder>()); | |||
} | |||
})); | |||
channel = await bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(ip), port)); | |||
} | |||
public async void SendAsync(byte[] data) | |||
{ | |||
if (channel == null) throw new NullReferenceException("Channel Not Open"); | |||
if (data == null) throw new ArgumentNullException("data is null"); | |||
if (channel.Open && channel.Active) | |||
{ | |||
await channel.WriteAndFlushAsync(Unpooled.WrappedBuffer(data)); | |||
} | |||
} | |||
private void Dispose(bool disposing) | |||
{ | |||
if (disposed) | |||
{ | |||
return; | |||
} | |||
if (disposing) | |||
{ | |||
//清理托管资源 | |||
channel.CloseAsync(); | |||
group.ShutdownGracefullyAsync(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(3)); | |||
} | |||
//让类型知道自己已经被释放 | |||
disposed = true; | |||
} | |||
~SubordinateLinkClient() | |||
{ | |||
//必须为false | |||
//这表明,隐式清理时,只要处理非托管资源就可以了。 | |||
Dispose(false); | |||
} | |||
public void Dispose() | |||
{ | |||
//必须为true | |||
Dispose(true); | |||
//通知垃圾回收机制不再调用终结器(析构器) | |||
GC.SuppressFinalize(this); | |||
} | |||
} | |||
} |
@@ -0,0 +1,49 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using System.Threading; | |||
namespace JT809.DotNetty.Core.Metadata | |||
{ | |||
/// <summary> | |||
/// | |||
/// <see cref="Grpc.Core.Internal"/> | |||
/// </summary> | |||
public class JT809AtomicCounter | |||
{ | |||
long counter = 0; | |||
public JT809AtomicCounter(long initialCount = 0) | |||
{ | |||
this.counter = initialCount; | |||
} | |||
public void Reset() | |||
{ | |||
Interlocked.Exchange(ref counter, 0); | |||
} | |||
public long Increment() | |||
{ | |||
return Interlocked.Increment(ref counter); | |||
} | |||
public long Add(long len) | |||
{ | |||
return Interlocked.Add(ref counter,len); | |||
} | |||
public long Decrement() | |||
{ | |||
return Interlocked.Decrement(ref counter); | |||
} | |||
public long Count | |||
{ | |||
get | |||
{ | |||
return Interlocked.Read(ref counter); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,23 @@ | |||
using JT809.Protocol; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
namespace JT809.DotNetty.Core.Metadata | |||
{ | |||
public class JT809Request | |||
{ | |||
public JT809Package Package { get; } | |||
/// <summary> | |||
/// 用于消息发送 | |||
/// </summary> | |||
public byte[] OriginalPackage { get;} | |||
public JT809Request(JT809Package package, byte[] originalPackage) | |||
{ | |||
Package = package; | |||
OriginalPackage = originalPackage; | |||
} | |||
} | |||
} |
@@ -0,0 +1,27 @@ | |||
using JT809.Protocol; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
namespace JT809.DotNetty.Core.Metadata | |||
{ | |||
public class JT809Response | |||
{ | |||
public JT809Package Package { get; set; } | |||
/// <summary> | |||
/// 根据实际情况适当调整包的大小 | |||
/// </summary> | |||
public int MinBufferSize { get; set; } | |||
public JT809Response() | |||
{ | |||
} | |||
public JT809Response(JT809Package package, int minBufferSize = 1024) | |||
{ | |||
Package = package; | |||
MinBufferSize = minBufferSize; | |||
} | |||
} | |||
} |
@@ -0,0 +1,28 @@ | |||
using DotNetty.Transport.Channels; | |||
using System; | |||
using JT809.Protocol.Enums; | |||
namespace JT809.DotNetty.Core.Metadata | |||
{ | |||
public class JT809TcpSession | |||
{ | |||
public JT809TcpSession(IChannel channel, uint msgGNSSCENTERID) | |||
{ | |||
MsgGNSSCENTERID = msgGNSSCENTERID; | |||
Channel = channel; | |||
StartTime = DateTime.Now; | |||
LastActiveTime = DateTime.Now; | |||
} | |||
/// <summary> | |||
/// 下级平台接入码,上级平台给下级平台分配唯一标识码。 | |||
/// </summary> | |||
public uint MsgGNSSCENTERID { get; set; } | |||
public IChannel Channel { get;} | |||
public DateTime LastActiveTime { get; set; } | |||
public DateTime StartTime { get; } | |||
} | |||
} |
@@ -0,0 +1,30 @@ | |||
using JT809.DotNetty.Abstractions.Dtos; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
using System.Text; | |||
namespace JT809.DotNetty.Core.Services | |||
{ | |||
/// <summary> | |||
/// 简单系统收集服务 | |||
/// </summary> | |||
public class JT809SimpleSystemCollectService | |||
{ | |||
/// <summary> | |||
/// 获取系统当前进程使用情况 | |||
/// </summary> | |||
/// <returns></returns> | |||
public JT809SystemCollectInfoDto Get() | |||
{ | |||
JT809SystemCollectInfoDto jT808SystemCollectInfoDto = new JT809SystemCollectInfoDto(); | |||
var proc = Process.GetCurrentProcess(); | |||
jT808SystemCollectInfoDto.ProcessId = proc.Id; | |||
jT808SystemCollectInfoDto.WorkingSet64 = proc.WorkingSet64 / 1024.0 / 1024.0; | |||
jT808SystemCollectInfoDto.PeakWorkingSet64 = proc.PeakWorkingSet64 / 1024.0 / 1024.0; | |||
jT808SystemCollectInfoDto.PrivateMemorySize64 = proc.PrivateMemorySize64 / 1024.0 / 1024.0; | |||
jT808SystemCollectInfoDto.CPUTotalProcessorTime = proc.TotalProcessorTime; | |||
return jT808SystemCollectInfoDto; | |||
} | |||
} | |||
} |
@@ -0,0 +1,51 @@ | |||
using JT809.DotNetty.Core.Metadata; | |||
namespace JT809.DotNetty.Core.Services | |||
{ | |||
/// <summary> | |||
/// Tcp计数包服务 | |||
/// </summary> | |||
public class JT809TcpAtomicCounterService | |||
{ | |||
private readonly JT809AtomicCounter MsgSuccessCounter = new JT809AtomicCounter(); | |||
private readonly JT809AtomicCounter MsgFailCounter = new JT809AtomicCounter(); | |||
public JT809TcpAtomicCounterService() | |||
{ | |||
} | |||
public void Reset() | |||
{ | |||
MsgSuccessCounter.Reset(); | |||
MsgFailCounter.Reset(); | |||
} | |||
public long MsgSuccessIncrement() | |||
{ | |||
return MsgSuccessCounter.Increment(); | |||
} | |||
public long MsgSuccessCount | |||
{ | |||
get | |||
{ | |||
return MsgSuccessCounter.Count; | |||
} | |||
} | |||
public long MsgFailIncrement() | |||
{ | |||
return MsgFailCounter.Increment(); | |||
} | |||
public long MsgFailCount | |||
{ | |||
get | |||
{ | |||
return MsgFailCounter.Count; | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,108 @@ | |||
using Microsoft.Extensions.Logging; | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using DotNetty.Transport.Channels; | |||
using JT809.DotNetty.Abstractions; | |||
using JT809.DotNetty.Core.Metadata; | |||
namespace JT809.DotNetty.Core | |||
{ | |||
/// <summary> | |||
/// JT809 Tcp会话管理 | |||
/// </summary> | |||
public class JT809TcpSessionManager | |||
{ | |||
private readonly ILogger<JT809TcpSessionManager> logger; | |||
private readonly IJT809SessionPublishing jT809SessionPublishing; | |||
public JT809TcpSessionManager( | |||
IJT809SessionPublishing jT809SessionPublishing, | |||
ILoggerFactory loggerFactory) | |||
{ | |||
this.jT809SessionPublishing = jT809SessionPublishing; | |||
logger = loggerFactory.CreateLogger<JT809TcpSessionManager>(); | |||
} | |||
private ConcurrentDictionary<uint, JT809TcpSession> SessionIdDict = new ConcurrentDictionary<uint, JT809TcpSession>(); | |||
public int SessionCount | |||
{ | |||
get | |||
{ | |||
return SessionIdDict.Count; | |||
} | |||
} | |||
public JT809TcpSession GetSession(uint msgGNSSCENTERID) | |||
{ | |||
if (SessionIdDict.TryGetValue(msgGNSSCENTERID, out JT809TcpSession targetSession)) | |||
{ | |||
return targetSession; | |||
} | |||
else | |||
{ | |||
return default; | |||
} | |||
} | |||
public void Heartbeat(uint msgGNSSCENTERID) | |||
{ | |||
if (SessionIdDict.TryGetValue(msgGNSSCENTERID, out JT809TcpSession oldjT808Session)) | |||
{ | |||
oldjT808Session.LastActiveTime = DateTime.Now; | |||
SessionIdDict.TryUpdate(msgGNSSCENTERID, oldjT808Session, oldjT808Session); | |||
} | |||
} | |||
public void TryAdd(JT809TcpSession appSession) | |||
{ | |||
if (SessionIdDict.TryAdd(appSession.MsgGNSSCENTERID, appSession)) | |||
{ | |||
jT809SessionPublishing.PublishAsync(JT809Constants.SessionOnline, appSession.MsgGNSSCENTERID.ToString()); | |||
} | |||
} | |||
public JT809TcpSession RemoveSession(uint msgGNSSCENTERID) | |||
{ | |||
//可以使用任意mq的发布订阅 | |||
if (!SessionIdDict.TryGetValue(msgGNSSCENTERID, out JT809TcpSession jT808Session)) | |||
{ | |||
return default; | |||
} | |||
if (SessionIdDict.TryRemove(msgGNSSCENTERID, out JT809TcpSession jT808SessionRemove)) | |||
{ | |||
logger.LogInformation($">>>{msgGNSSCENTERID} Session Remove."); | |||
jT809SessionPublishing.PublishAsync(JT809Constants.SessionOffline, msgGNSSCENTERID.ToString()); | |||
return jT808SessionRemove; | |||
} | |||
else | |||
{ | |||
return default; | |||
} | |||
} | |||
public void RemoveSessionByChannel(IChannel channel) | |||
{ | |||
var keys = SessionIdDict.Where(w => w.Value.Channel.Id == channel.Id).Select(s => s.Key).ToList(); | |||
if (keys.Count > 0) | |||
{ | |||
foreach (var key in keys) | |||
{ | |||
SessionIdDict.TryRemove(key, out JT809TcpSession jT808SessionRemove); | |||
} | |||
string nos = string.Join(",", keys); | |||
logger.LogInformation($">>>{nos} Channel Remove."); | |||
jT809SessionPublishing.PublishAsync(JT809Constants.SessionOffline, nos); | |||
} | |||
} | |||
public IEnumerable<JT809TcpSession> GetAll() | |||
{ | |||
return SessionIdDict.Select(s => s.Value).ToList(); | |||
} | |||
} | |||
} | |||
@@ -0,0 +1,18 @@ | |||
using JT809.DotNetty.Core; | |||
using JT809.DotNetty.Core.Handlers; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.DotNetty.Tcp.Handlers | |||
{ | |||
/// <summary> | |||
/// 默认消息处理业务实现 | |||
/// </summary> | |||
internal class JT809MsgIdDefaultTcpHandler : JT809MsgIdTcpHandlerBase | |||
{ | |||
public JT809MsgIdDefaultTcpHandler(JT809TcpSessionManager sessionManager) : base(sessionManager) | |||
{ | |||
} | |||
} | |||
} |
@@ -0,0 +1,98 @@ | |||
using DotNetty.Handlers.Timeout; | |||
using DotNetty.Transport.Channels; | |||
using JT809.DotNetty.Core; | |||
using Microsoft.Extensions.Logging; | |||
using System; | |||
using System.Threading.Tasks; | |||
namespace JT809.DotNetty.Tcp.Handlers | |||
{ | |||
/// <summary> | |||
/// JT809服务通道处理程序 | |||
/// </summary> | |||
internal class JT809TcpConnectionHandler : ChannelHandlerAdapter | |||
{ | |||
private readonly ILogger<JT809TcpConnectionHandler> logger; | |||
private readonly JT809TcpSessionManager jT809SessionManager; | |||
public JT809TcpConnectionHandler( | |||
JT809TcpSessionManager jT809SessionManager, | |||
ILoggerFactory loggerFactory) | |||
{ | |||
this.jT809SessionManager = jT809SessionManager; | |||
logger = loggerFactory.CreateLogger<JT809TcpConnectionHandler>(); | |||
} | |||
/// <summary> | |||
/// 通道激活 | |||
/// </summary> | |||
/// <param name="context"></param> | |||
public override void ChannelActive(IChannelHandlerContext context) | |||
{ | |||
string channelId = context.Channel.Id.AsShortText(); | |||
if (logger.IsEnabled(LogLevel.Debug)) | |||
logger.LogDebug($"<<<{ channelId } Successful client connection to server."); | |||
base.ChannelActive(context); | |||
} | |||
/// <summary> | |||
/// 设备主动断开 | |||
/// </summary> | |||
/// <param name="context"></param> | |||
public override void ChannelInactive(IChannelHandlerContext context) | |||
{ | |||
string channelId = context.Channel.Id.AsShortText(); | |||
if (logger.IsEnabled(LogLevel.Debug)) | |||
logger.LogDebug($">>>{ channelId } The client disconnects from the server."); | |||
jT809SessionManager.RemoveSessionByChannel(context.Channel); | |||
base.ChannelInactive(context); | |||
} | |||
/// <summary> | |||
/// 服务器主动断开 | |||
/// </summary> | |||
/// <param name="context"></param> | |||
/// <returns></returns> | |||
public override Task CloseAsync(IChannelHandlerContext context) | |||
{ | |||
string channelId = context.Channel.Id.AsShortText(); | |||
if (logger.IsEnabled(LogLevel.Debug)) | |||
logger.LogDebug($"<<<{ channelId } The server disconnects from the client."); | |||
jT809SessionManager.RemoveSessionByChannel(context.Channel); | |||
return base.CloseAsync(context); | |||
} | |||
public override void ChannelReadComplete(IChannelHandlerContext context)=> context.Flush(); | |||
/// <summary> | |||
/// 超时策略 | |||
/// </summary> | |||
/// <param name="context"></param> | |||
/// <param name="evt"></param> | |||
public override void UserEventTriggered(IChannelHandlerContext context, object evt) | |||
{ | |||
IdleStateEvent idleStateEvent = evt as IdleStateEvent; | |||
if (idleStateEvent != null) | |||
{ | |||
if(idleStateEvent.State== IdleState.ReaderIdle) | |||
{ | |||
string channelId = context.Channel.Id.AsShortText(); | |||
logger.LogInformation($"{idleStateEvent.State.ToString()}>>>{channelId}"); | |||
jT809SessionManager.RemoveSessionByChannel(context.Channel); | |||
context.CloseAsync(); | |||
} | |||
} | |||
base.UserEventTriggered(context, evt); | |||
} | |||
public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) | |||
{ | |||
string channelId = context.Channel.Id.AsShortText(); | |||
logger.LogError(exception,$"{channelId} {exception.Message}" ); | |||
jT809SessionManager.RemoveSessionByChannel(context.Channel); | |||
context.CloseAsync(); | |||
} | |||
} | |||
} | |||
@@ -0,0 +1,83 @@ | |||
using DotNetty.Buffers; | |||
using DotNetty.Transport.Channels; | |||
using JT809.Protocol; | |||
using System; | |||
using Microsoft.Extensions.Logging; | |||
using JT809.Protocol.Exceptions; | |||
using JT809.DotNetty.Core.Services; | |||
using JT809.DotNetty.Core; | |||
using JT809.DotNetty.Core.Handlers; | |||
using JT809.DotNetty.Core.Metadata; | |||
namespace JT809.DotNetty.Tcp.Handlers | |||
{ | |||
/// <summary> | |||
/// JT809服务端处理程序 | |||
/// </summary> | |||
internal class JT809TcpServerHandler : SimpleChannelInboundHandler<byte[]> | |||
{ | |||
private readonly JT809MsgIdTcpHandlerBase handler; | |||
private readonly JT809TcpSessionManager jT809SessionManager; | |||
private readonly JT809TcpAtomicCounterService jT809AtomicCounterService; | |||
private readonly ILogger<JT809TcpServerHandler> logger; | |||
public JT809TcpServerHandler( | |||
ILoggerFactory loggerFactory, | |||
JT809MsgIdTcpHandlerBase handler, | |||
JT809TcpAtomicCounterService jT809AtomicCounterService, | |||
JT809TcpSessionManager jT809SessionManager | |||
) | |||
{ | |||
this.handler = handler; | |||
this.jT809SessionManager = jT809SessionManager; | |||
this.jT809AtomicCounterService = jT809AtomicCounterService; | |||
logger = loggerFactory.CreateLogger<JT809TcpServerHandler>(); | |||
} | |||
protected override void ChannelRead0(IChannelHandlerContext ctx, byte[] msg) | |||
{ | |||
try | |||
{ | |||
JT809Package jT809Package = JT809Serializer.Deserialize(msg); | |||
jT809AtomicCounterService.MsgSuccessIncrement(); | |||
if (logger.IsEnabled(LogLevel.Debug)) | |||
{ | |||
logger.LogDebug("accept package success count<<<" + jT809AtomicCounterService.MsgSuccessCount.ToString()); | |||
} | |||
jT809SessionManager.TryAdd(new JT809TcpSession(ctx.Channel, jT809Package.Header.MsgGNSSCENTERID)); | |||
Func<JT809Request, JT809Response> handlerFunc; | |||
if (handler.HandlerDict.TryGetValue(jT809Package.Header.BusinessType, out handlerFunc)) | |||
{ | |||
JT809Response jT808Response = handlerFunc(new JT809Request(jT809Package, msg)); | |||
if (jT808Response != null) | |||
{ | |||
var sendData = JT809Serializer.Serialize(jT808Response.Package, jT808Response.MinBufferSize); | |||
ctx.WriteAndFlushAsync(Unpooled.WrappedBuffer(sendData)); | |||
} | |||
} | |||
} | |||
catch (JT809Exception ex) | |||
{ | |||
jT809AtomicCounterService.MsgFailIncrement(); | |||
if (logger.IsEnabled(LogLevel.Error)) | |||
{ | |||
logger.LogError("accept package fail count<<<" + jT809AtomicCounterService.MsgFailCount.ToString()); | |||
logger.LogError(ex, "accept msg<<<" + ByteBufferUtil.HexDump(msg)); | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
jT809AtomicCounterService.MsgFailIncrement(); | |||
if (logger.IsEnabled(LogLevel.Error)) | |||
{ | |||
logger.LogError("accept package fail count<<<" + jT809AtomicCounterService.MsgFailCount.ToString()); | |||
logger.LogError(ex, "accept msg<<<" + ByteBufferUtil.HexDump(msg)); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,11 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<PropertyGroup> | |||
<TargetFramework>netstandard2.0</TargetFramework> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\JT809.DotNetty.Core\JT809.DotNetty.Core.csproj" /> | |||
</ItemGroup> | |||
</Project> |
@@ -0,0 +1,32 @@ | |||
using JT809.DotNetty.Core; | |||
using JT809.DotNetty.Core.Codecs; | |||
using JT809.DotNetty.Core.Handlers; | |||
using JT809.DotNetty.Core.Services; | |||
using JT809.DotNetty.Tcp.Handlers; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.DependencyInjection.Extensions; | |||
using Microsoft.Extensions.Hosting; | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Reflection; | |||
using System.Runtime.CompilerServices; | |||
[assembly: InternalsVisibleTo("JT809.DotNetty.Tcp.Test")] | |||
namespace JT809.DotNetty.Tcp | |||
{ | |||
public static class JT809TcpDotnettyExtensions | |||
{ | |||
public static IServiceCollection AddJT809TcpHost(this IServiceCollection serviceDescriptors) | |||
{ | |||
serviceDescriptors.TryAddSingleton<JT809TcpSessionManager>(); | |||
serviceDescriptors.TryAddSingleton<JT809TcpAtomicCounterService>(); | |||
serviceDescriptors.TryAddSingleton<JT809MsgIdTcpHandlerBase, JT809MsgIdDefaultTcpHandler>(); | |||
serviceDescriptors.TryAddScoped<JT809TcpConnectionHandler>(); | |||
serviceDescriptors.TryAddScoped<JT809TcpDecoder>(); | |||
serviceDescriptors.TryAddScoped<JT809TcpServerHandler>(); | |||
serviceDescriptors.AddHostedService<JT809TcpServerHost>(); | |||
return serviceDescriptors; | |||
} | |||
} | |||
} |
@@ -0,0 +1,95 @@ | |||
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.Tcp.Handlers; | |||
namespace JT809.DotNetty.Tcp | |||
{ | |||
/// <summary> | |||
/// JT809 Tcp网关服务 | |||
/// </summary> | |||
internal class JT809TcpServerHost : IHostedService | |||
{ | |||
private readonly IServiceProvider serviceProvider; | |||
private readonly JT809Configuration configuration; | |||
private readonly ILogger<JT809TcpServerHost> logger; | |||
private DispatcherEventLoopGroup bossGroup; | |||
private WorkerEventLoopGroup workerGroup; | |||
private IChannel bootstrapChannel; | |||
private IByteBufferAllocator serverBufferAllocator; | |||
public JT809TcpServerHost( | |||
IServiceProvider provider, | |||
ILoggerFactory loggerFactory, | |||
IOptions<JT809Configuration> jT809ConfigurationAccessor) | |||
{ | |||
serviceProvider = provider; | |||
configuration = jT809ConfigurationAccessor.Value; | |||
logger=loggerFactory.CreateLogger<JT809TcpServerHost>(); | |||
} | |||
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<TcpServerChannel>(); | |||
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<IChannel>(channel => | |||
{ | |||
IChannelPipeline pipeline = channel.Pipeline; | |||
using (var scope = serviceProvider.CreateScope()) | |||
{ | |||
channel.Pipeline.AddLast("jt809SystemIdleState", new IdleStateHandler( | |||
configuration.ReaderIdleTimeSeconds, | |||
configuration.WriterIdleTimeSeconds, | |||
configuration.AllIdleTimeSeconds)); | |||
channel.Pipeline.AddLast("jt809TcpConnection", scope.ServiceProvider.GetRequiredService<JT809TcpConnectionHandler>()); | |||
channel.Pipeline.AddLast("jt809TcpBuffer", new DelimiterBasedFrameDecoder(int.MaxValue, | |||
Unpooled.CopiedBuffer(new byte[] { JT809Package.BEGINFLAG }), | |||
Unpooled.CopiedBuffer(new byte[] { JT809Package.ENDFLAG }))); | |||
channel.Pipeline.AddLast("jt809TcpDecode", scope.ServiceProvider.GetRequiredService<JT809TcpDecoder>()); | |||
channel.Pipeline.AddLast("jt809TcpService", scope.ServiceProvider.GetRequiredService<JT809TcpServerHandler>()); | |||
} | |||
})); | |||
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); | |||
} | |||
} | |||
} |
@@ -0,0 +1,27 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<PropertyGroup> | |||
<OutputType>Exe</OutputType> | |||
<TargetFramework>netcoreapp2.2</TargetFramework> | |||
<LangVersion>7.3</LangVersion> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" /> | |||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" /> | |||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="2.2.0" /> | |||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.2.0" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\..\JT809.DotNetty.Tcp\JT809.DotNetty.Tcp.csproj" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<None Update="appsettings.json"> | |||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | |||
</None> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<None Update="appsettings.json"> | |||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | |||
</None> | |||
</ItemGroup> | |||
</Project> |
@@ -0,0 +1,54 @@ | |||
using JT809.DotNetty.Core; | |||
using JT809.DotNetty.Tcp; | |||
using JT809.Protocol.Configs; | |||
using Microsoft.Extensions.Configuration; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.Hosting; | |||
using Microsoft.Extensions.Logging; | |||
using System; | |||
using System.Threading.Tasks; | |||
namespace JT809.DotNetty.Host.Test | |||
{ | |||
class Program | |||
{ | |||
static async Task Main(string[] args) | |||
{ | |||
JT809.Protocol.JT809GlobalConfig.Instance | |||
.SetHeaderOptions(new JT809HeaderOptions | |||
{ | |||
MsgGNSSCENTERID = 20190222, | |||
Version = new JT809.Protocol.JT809Header_Version(1, 0, 0), | |||
EncryptKey = 9595 | |||
}); | |||
//主链路登录请求消息 | |||
//5B000000480000008510010134140E010000000000270F0134140E32303139303232323132372E302E302E31000000000000000000000000000000000000000000000003297B8D5D | |||
//主链路注销请求消息 | |||
//5B000000260000008510030134140E010000000000270F0001E24031323334353600003FE15D | |||
//主链路连接保持请求消息 | |||
//5B0000001A0000008510050134140E010000000000270FBA415D | |||
var serverHostBuilder = new HostBuilder() | |||
.ConfigureAppConfiguration((hostingContext, config) => | |||
{ | |||
config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory); | |||
config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); | |||
}) | |||
.ConfigureLogging((context, logging) => | |||
{ | |||
logging.AddConsole(); | |||
logging.SetMinimumLevel(LogLevel.Trace); | |||
}) | |||
.ConfigureServices((hostContext, services) => | |||
{ | |||
services.AddSingleton<ILoggerFactory, LoggerFactory>(); | |||
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); | |||
services.AddJT809Core(hostContext.Configuration) | |||
.AddJT809TcpHost(); | |||
}); | |||
await serverHostBuilder.RunConsoleAsync(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,18 @@ | |||
{ | |||
"Logging": { | |||
"IncludeScopes": false, | |||
"Debug": { | |||
"LogLevel": { | |||
"Default": "Trace" | |||
} | |||
}, | |||
"Console": { | |||
"LogLevel": { | |||
"Default": "Trace" | |||
} | |||
} | |||
}, | |||
"JT809Configuration": { | |||
} | |||
} |
@@ -0,0 +1,31 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<PropertyGroup> | |||
<TargetFramework>netcoreapp2.2</TargetFramework> | |||
<IsPackable>false</IsPackable> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" /> | |||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" /> | |||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="2.2.0" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<None Update="appsettings.json"> | |||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | |||
</None> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" /> | |||
<PackageReference Include="xunit" Version="2.4.0" /> | |||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\..\JT809.DotNetty.Tcp\JT809.DotNetty.Tcp.csproj" /> | |||
</ItemGroup> | |||
</Project> |
@@ -0,0 +1,37 @@ | |||
using JT809.DotNetty.Core; | |||
using Microsoft.Extensions.Configuration; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using Microsoft.Extensions.Hosting; | |||
using Microsoft.Extensions.Logging; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT809.DotNetty.Tcp.Test | |||
{ | |||
public class TestBase | |||
{ | |||
public static IServiceProvider ServiceProvider; | |||
static TestBase() | |||
{ | |||
var serverHostBuilder = new HostBuilder() | |||
.ConfigureAppConfiguration((hostingContext, config) => | |||
{ | |||
config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory); | |||
config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); | |||
}) | |||
.ConfigureServices((hostContext, services) => | |||
{ | |||
services.AddSingleton<ILoggerFactory, LoggerFactory>(); | |||
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); | |||
services.AddJT809Core(hostContext.Configuration) | |||
.AddJT809TcpHost(); | |||
}); | |||
var build = serverHostBuilder.Build(); | |||
build.Start(); | |||
ServiceProvider = build.Services; | |||
} | |||
} | |||
} |
@@ -0,0 +1,18 @@ | |||
{ | |||
"Logging": { | |||
"IncludeScopes": false, | |||
"Debug": { | |||
"LogLevel": { | |||
"Default": "Trace" | |||
} | |||
}, | |||
"Console": { | |||
"LogLevel": { | |||
"Default": "Trace" | |||
} | |||
} | |||
}, | |||
"JT809Configuration": { | |||
} | |||
} |
@@ -0,0 +1,83 @@ | |||
| |||
Microsoft Visual Studio Solution File, Format Version 12.00 | |||
# Visual Studio 15 | |||
VisualStudioVersion = 15.0.28010.2016 | |||
MinimumVisualStudioVersion = 10.0.40219.1 | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT809Netty.Core", "JT809Netty.Core\JT809Netty.Core.csproj", "{2054D7E6-53B6-412F-BE9D-C6DABD80A111}" | |||
EndProject | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT809Netty.DownMasterLink", "JT809Netty.DownMasterLink\JT809Netty.DownMasterLink.csproj", "{3BF1D40D-A17D-4FBC-B3FF-B6DF8B3F13ED}" | |||
EndProject | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT809.DotNetty.Core", "JT809.DotNetty.Core\JT809.DotNetty.Core.csproj", "{0291C1D6-B4C6-4E7E-984B-0BAFB238727D}" | |||
EndProject | |||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C712B2DE-34FE-4D9C-B574-A08B019246E4}" | |||
EndProject | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT809.Protocol", "JT809.Protocol\src\JT809.Protocol\JT809.Protocol.csproj", "{321EE8EE-10D7-4233-8B8A-279BE68FB18A}" | |||
EndProject | |||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT809.DotNetty.Tcp", "JT809.DotNetty.Tcp\JT809.DotNetty.Tcp.csproj", "{9BE94CDE-E813-403A-A68B-45C78BCAAF74}" | |||
EndProject | |||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT809.DotNetty.Abstractions", "JT809.DotNetty.Abstractions\JT809.DotNetty.Abstractions.csproj", "{EB8276CC-1848-4E7D-B77E-29B22AF767F0}" | |||
EndProject | |||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{DD4611CF-79A9-45C7-91EB-1E84D22B7D07}" | |||
EndProject | |||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT809.DotNetty.Tcp.Test", "JT809.DotNetty.Tests\JT809.DotNetty.Tcp.Test\JT809.DotNetty.Tcp.Test.csproj", "{560913C8-B618-46AD-B974-9D324F1ABBAC}" | |||
EndProject | |||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT809.DotNetty.Host.Test", "JT809.DotNetty.Tests\JT809.DotNetty.Host.Test\JT809.DotNetty.Host.Test.csproj", "{D4E18559-C429-416F-9399-42C0E604D27B}" | |||
EndProject | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT809.Protocol.Extensions.DependencyInjection", "JT809.Protocol\src\JT809.Protocol.Extensions.DependencyInjection\JT809.Protocol.Extensions.DependencyInjection.csproj", "{975D959C-7C0B-418E-838E-EB383E912F8C}" | |||
EndProject | |||
Global | |||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||
Debug|Any CPU = Debug|Any CPU | |||
Release|Any CPU = Release|Any CPU | |||
EndGlobalSection | |||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||
{2054D7E6-53B6-412F-BE9D-C6DABD80A111}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{2054D7E6-53B6-412F-BE9D-C6DABD80A111}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{2054D7E6-53B6-412F-BE9D-C6DABD80A111}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{2054D7E6-53B6-412F-BE9D-C6DABD80A111}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{3BF1D40D-A17D-4FBC-B3FF-B6DF8B3F13ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{3BF1D40D-A17D-4FBC-B3FF-B6DF8B3F13ED}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{3BF1D40D-A17D-4FBC-B3FF-B6DF8B3F13ED}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{3BF1D40D-A17D-4FBC-B3FF-B6DF8B3F13ED}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{0291C1D6-B4C6-4E7E-984B-0BAFB238727D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{0291C1D6-B4C6-4E7E-984B-0BAFB238727D}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{0291C1D6-B4C6-4E7E-984B-0BAFB238727D}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{0291C1D6-B4C6-4E7E-984B-0BAFB238727D}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{321EE8EE-10D7-4233-8B8A-279BE68FB18A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{321EE8EE-10D7-4233-8B8A-279BE68FB18A}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{321EE8EE-10D7-4233-8B8A-279BE68FB18A}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{321EE8EE-10D7-4233-8B8A-279BE68FB18A}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{9BE94CDE-E813-403A-A68B-45C78BCAAF74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{9BE94CDE-E813-403A-A68B-45C78BCAAF74}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{9BE94CDE-E813-403A-A68B-45C78BCAAF74}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{9BE94CDE-E813-403A-A68B-45C78BCAAF74}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{EB8276CC-1848-4E7D-B77E-29B22AF767F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{EB8276CC-1848-4E7D-B77E-29B22AF767F0}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{EB8276CC-1848-4E7D-B77E-29B22AF767F0}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{EB8276CC-1848-4E7D-B77E-29B22AF767F0}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{560913C8-B618-46AD-B974-9D324F1ABBAC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{560913C8-B618-46AD-B974-9D324F1ABBAC}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{560913C8-B618-46AD-B974-9D324F1ABBAC}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{560913C8-B618-46AD-B974-9D324F1ABBAC}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{D4E18559-C429-416F-9399-42C0E604D27B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{D4E18559-C429-416F-9399-42C0E604D27B}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{D4E18559-C429-416F-9399-42C0E604D27B}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{D4E18559-C429-416F-9399-42C0E604D27B}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{975D959C-7C0B-418E-838E-EB383E912F8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{975D959C-7C0B-418E-838E-EB383E912F8C}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{975D959C-7C0B-418E-838E-EB383E912F8C}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{975D959C-7C0B-418E-838E-EB383E912F8C}.Release|Any CPU.Build.0 = Release|Any CPU | |||
EndGlobalSection | |||
GlobalSection(SolutionProperties) = preSolution | |||
HideSolutionNode = FALSE | |||
EndGlobalSection | |||
GlobalSection(NestedProjects) = preSolution | |||
{321EE8EE-10D7-4233-8B8A-279BE68FB18A} = {C712B2DE-34FE-4D9C-B574-A08B019246E4} | |||
{560913C8-B618-46AD-B974-9D324F1ABBAC} = {DD4611CF-79A9-45C7-91EB-1E84D22B7D07} | |||
{D4E18559-C429-416F-9399-42C0E604D27B} = {DD4611CF-79A9-45C7-91EB-1E84D22B7D07} | |||
{975D959C-7C0B-418E-838E-EB383E912F8C} = {C712B2DE-34FE-4D9C-B574-A08B019246E4} | |||
EndGlobalSection | |||
GlobalSection(ExtensibilityGlobals) = postSolution | |||
SolutionGuid = {0FC2A52E-3B7A-4485-9C3B-9080C825419D} | |||
EndGlobalSection | |||
EndGlobal |
@@ -1 +1 @@ | |||
Subproject commit b84dec6af9a812ea0ea02850987fd4455d1f20ee | |||
Subproject commit 359a347cec6a1ee1ce3544d8ca399a94cadd9484 |
@@ -1,31 +0,0 @@ | |||
| |||
Microsoft Visual Studio Solution File, Format Version 12.00 | |||
# Visual Studio 15 | |||
VisualStudioVersion = 15.0.28010.2016 | |||
MinimumVisualStudioVersion = 10.0.40219.1 | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT809Netty.Core", "JT809Netty.Core\JT809Netty.Core.csproj", "{2054D7E6-53B6-412F-BE9D-C6DABD80A111}" | |||
EndProject | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT809Netty.DownMasterLink", "JT809Netty.DownMasterLink\JT809Netty.DownMasterLink.csproj", "{3BF1D40D-A17D-4FBC-B3FF-B6DF8B3F13ED}" | |||
EndProject | |||
Global | |||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||
Debug|Any CPU = Debug|Any CPU | |||
Release|Any CPU = Release|Any CPU | |||
EndGlobalSection | |||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||
{2054D7E6-53B6-412F-BE9D-C6DABD80A111}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{2054D7E6-53B6-412F-BE9D-C6DABD80A111}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{2054D7E6-53B6-412F-BE9D-C6DABD80A111}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{2054D7E6-53B6-412F-BE9D-C6DABD80A111}.Release|Any CPU.Build.0 = Release|Any CPU | |||
{3BF1D40D-A17D-4FBC-B3FF-B6DF8B3F13ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||
{3BF1D40D-A17D-4FBC-B3FF-B6DF8B3F13ED}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||
{3BF1D40D-A17D-4FBC-B3FF-B6DF8B3F13ED}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||
{3BF1D40D-A17D-4FBC-B3FF-B6DF8B3F13ED}.Release|Any CPU.Build.0 = Release|Any CPU | |||
EndGlobalSection | |||
GlobalSection(SolutionProperties) = preSolution | |||
HideSolutionNode = FALSE | |||
EndGlobalSection | |||
GlobalSection(ExtensibilityGlobals) = postSolution | |||
SolutionGuid = {0FC2A52E-3B7A-4485-9C3B-9080C825419D} | |||
EndGlobalSection | |||
EndGlobal |