@@ -26,4 +26,20 @@ | |||||
> 前提条件:需要安装kafka以及zookeeper | > 前提条件:需要安装kafka以及zookeeper | ||||
 | |||||
 | |||||
## 作为下级平台(企业对企业) | |||||
### 作为客户端主链路 | |||||
主链路登录请求消息=>主链路登录应答消息=》成功=》主链路车辆动态信息交换_实时上传车辆定位信息消息 | |||||
当没有发送定位数据时,需要发送主链路连接保持请求消息(心跳)=>主链路连接保持应答消息 | |||||
### 作为服务端从链路 | |||||
从链路连接请求消息=>从链路连接应答消息 | |||||
从链路连接保持请求消息=>从链路连接保持应答消息 | |||||
> 注意:作为下级平台发送数据时,有些企业需要双链路,有些企业只需要主链路发送数据,不管从链路,这时候就需要一个简单的从链路网关只负责简单的保持链路畅通。 |
@@ -6,14 +6,19 @@ using DotNetty.Transport.Channels; | |||||
using DotNetty.Transport.Channels.Sockets; | using DotNetty.Transport.Channels.Sockets; | ||||
using JT809.DotNetty.Core.Codecs; | using JT809.DotNetty.Core.Codecs; | ||||
using JT809.DotNetty.Core.Handlers; | using JT809.DotNetty.Core.Handlers; | ||||
using JT809.DotNetty.Core.Interfaces; | |||||
using JT809.DotNetty.Core.Metadata; | using JT809.DotNetty.Core.Metadata; | ||||
using JT809.Protocol; | using JT809.Protocol; | ||||
using JT809.Protocol.Extensions; | |||||
using JT809.Protocol.MessageBody; | |||||
using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||
using Microsoft.Extensions.Logging; | using Microsoft.Extensions.Logging; | ||||
using Polly; | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Net; | using System.Net; | ||||
using System.Text; | using System.Text; | ||||
using System.Threading.Tasks; | |||||
namespace JT809.DotNetty.Core.Clients | namespace JT809.DotNetty.Core.Clients | ||||
{ | { | ||||
@@ -31,19 +36,20 @@ namespace JT809.DotNetty.Core.Clients | |||||
private readonly ILogger<JT809MainClient> logger; | private readonly ILogger<JT809MainClient> logger; | ||||
private readonly ILoggerFactory loggerFactory; | |||||
private readonly IServiceProvider serviceProvider; | private readonly IServiceProvider serviceProvider; | ||||
private bool disposed = false; | private bool disposed = false; | ||||
private readonly IJT809ManualResetEvent manualResetEvent; | |||||
public JT809MainClient( | public JT809MainClient( | ||||
IJT809ManualResetEvent jT809ManualResetEvent, | |||||
IServiceProvider provider, | IServiceProvider provider, | ||||
ILoggerFactory loggerFactory) | ILoggerFactory loggerFactory) | ||||
{ | { | ||||
this.serviceProvider = provider; | this.serviceProvider = provider; | ||||
this.loggerFactory = loggerFactory; | |||||
this.logger = loggerFactory.CreateLogger<JT809MainClient>(); | this.logger = loggerFactory.CreateLogger<JT809MainClient>(); | ||||
this.manualResetEvent = jT809ManualResetEvent; | |||||
group = new MultithreadEventLoopGroup(); | group = new MultithreadEventLoopGroup(); | ||||
bootstrap = new Bootstrap(); | bootstrap = new Bootstrap(); | ||||
bootstrap.Group(group) | bootstrap.Group(group) | ||||
@@ -63,24 +69,43 @@ namespace JT809.DotNetty.Core.Clients | |||||
pipeline.AddLast("jt809MainClientEncode", scope.ServiceProvider.GetRequiredService<JT809Encoder>()); | pipeline.AddLast("jt809MainClientEncode", scope.ServiceProvider.GetRequiredService<JT809Encoder>()); | ||||
pipeline.AddLast("jt809MainClientDecode", scope.ServiceProvider.GetRequiredService<JT809Decoder>()); | pipeline.AddLast("jt809MainClientDecode", scope.ServiceProvider.GetRequiredService<JT809Decoder>()); | ||||
pipeline.AddLast("jt809MainClientConnection", scope.ServiceProvider.GetRequiredService<JT809MainClientConnectionHandler>()); | pipeline.AddLast("jt809MainClientConnection", scope.ServiceProvider.GetRequiredService<JT809MainClientConnectionHandler>()); | ||||
pipeline.AddLast("jt809MainClientServer", scope.ServiceProvider.GetRequiredService<JT809MainServerHandler>()); | |||||
pipeline.AddLast("jt809MainClientServer", scope.ServiceProvider.GetRequiredService<JT809MainClientHandler>()); | |||||
} | } | ||||
})); | })); | ||||
} | } | ||||
public async void ConnectAsync(string ip,int port) | |||||
private JT809_0x1001 _jT809_0x1001; | |||||
private IPEndPoint iPEndPoint; | |||||
public async Task<bool> Login( | |||||
string ip, | |||||
int port, | |||||
JT809_0x1001 jT809_0x1001) | |||||
{ | { | ||||
if (disposed) return await Task.FromResult(false); | |||||
logger.LogInformation($"ip:{ip},port:{port}"); | logger.LogInformation($"ip:{ip},port:{port}"); | ||||
this._jT809_0x1001 = jT809_0x1001; | |||||
this.iPEndPoint = new IPEndPoint(IPAddress.Parse(ip), port); | |||||
bool successed = false; | |||||
try | try | ||||
{ | { | ||||
//IPAddress[] hostinfo = Dns.GetHostAddresses(host); | |||||
//IPAddress address = hostinfo[0]; | |||||
if (channel == null) | if (channel == null) | ||||
{ | { | ||||
channel = await bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(ip), port)); | |||||
} | |||||
else | |||||
{ | |||||
await channel.CloseAsync(); | |||||
channel = await bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(ip), port)); | |||||
channel = await bootstrap.ConnectAsync(iPEndPoint); | |||||
successed = channel.Open && channel.Active; | |||||
if (channel.Open && channel.Active) | |||||
{ | |||||
//JT809.Protocol.MessageBody.JT809_0x1001 jT809_0X1001 = jT809_0X1001 new Protocol.MessageBody.JT809_0x1001(); | |||||
//jT809_0X1001.DownLinkIP = downLinkIP; | |||||
//jT809_0X1001.DownLinkPort = downLinkPort; | |||||
//jT809_0X1001.UserId = userId; | |||||
//jT809_0X1001.Password = password; | |||||
var package = JT809.Protocol.Enums.JT809BusinessType.主链路登录请求消息.Create(_jT809_0x1001); | |||||
await channel.WriteAndFlushAsync(new JT809Response(package, 100)); | |||||
logger.LogInformation("等待登录应答结果..."); | |||||
manualResetEvent.Pause(); | |||||
} | |||||
} | } | ||||
} | } | ||||
catch (AggregateException ex) | catch (AggregateException ex) | ||||
@@ -91,16 +116,40 @@ namespace JT809.DotNetty.Core.Clients | |||||
{ | { | ||||
logger.LogError(ex, $"ip:{ip},port:{port}"); | logger.LogError(ex, $"ip:{ip},port:{port}"); | ||||
} | } | ||||
return await Task.FromResult(successed); | |||||
} | } | ||||
public async void SendAsync(JT809Response jT809Response) | public async void SendAsync(JT809Response jT809Response) | ||||
{ | { | ||||
if (disposed) return; | |||||
if (channel == null) throw new NullReferenceException("Channel Not Open"); | if (channel == null) throw new NullReferenceException("Channel Not Open"); | ||||
if (jT809Response == null) throw new ArgumentNullException("Data is null"); | if (jT809Response == null) throw new ArgumentNullException("Data is null"); | ||||
if (channel.Open && channel.Active) | if (channel.Open && channel.Active) | ||||
{ | { | ||||
manualResetEvent.Pause(); | |||||
await channel.WriteAndFlushAsync(jT809Response); | await channel.WriteAndFlushAsync(jT809Response); | ||||
} | } | ||||
else | |||||
{ | |||||
manualResetEvent.Reset(); | |||||
_ = Policy.HandleResult(channel.Open && channel.Active) | |||||
.WaitAndRetryForeverAsync(retryAttempt => | |||||
{ | |||||
return TimeSpan.FromSeconds(10); | |||||
}, (exception, timespan, ctx) => | |||||
{ | |||||
logger.LogError($"服务端断开{channel.RemoteAddress},重试结果{exception.Result},重试次数{timespan},下次重试间隔(s){ctx.TotalSeconds}"); | |||||
}) | |||||
.ExecuteAsync(async () => | |||||
{ | |||||
channel = await bootstrap.ConnectAsync(iPEndPoint); | |||||
var package = JT809.Protocol.Enums.JT809BusinessType.主链路登录请求消息.Create(_jT809_0x1001); | |||||
await channel.WriteAndFlushAsync(new JT809Response(package, 100)); | |||||
logger.LogInformation("尝试重连,等待登录应答结果..."); | |||||
manualResetEvent.Pause(); | |||||
return await Task.FromResult(channel.Open && channel.Active); | |||||
}); | |||||
} | |||||
} | } | ||||
private void Dispose(bool disposing) | private void Dispose(bool disposing) | ||||
@@ -0,0 +1,33 @@ | |||||
using JT809.DotNetty.Core.Interfaces; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using System.Threading; | |||||
namespace JT809.DotNetty.Core.Events | |||||
{ | |||||
public class JT809InferoprManualResetEvent: IJT809ManualResetEvent | |||||
{ | |||||
private ManualResetEvent ManualResetEvent; | |||||
public JT809InferoprManualResetEvent() | |||||
{ | |||||
ManualResetEvent = new ManualResetEvent(false); | |||||
} | |||||
public void Pause() | |||||
{ | |||||
ManualResetEvent.WaitOne(); | |||||
} | |||||
public bool Reset() | |||||
{ | |||||
return ManualResetEvent.Reset(); | |||||
} | |||||
public bool Resume() | |||||
{ | |||||
return ManualResetEvent.Set(); | |||||
} | |||||
} | |||||
} |
@@ -9,6 +9,7 @@ using JT809.Protocol.Extensions; | |||||
using JT809.Protocol.MessageBody; | using JT809.Protocol.MessageBody; | ||||
using Microsoft.Extensions.Logging; | using Microsoft.Extensions.Logging; | ||||
using Microsoft.Extensions.Options; | using Microsoft.Extensions.Options; | ||||
using Newtonsoft.Json; | |||||
namespace JT809.DotNetty.Core.Handlers | namespace JT809.DotNetty.Core.Handlers | ||||
{ | { | ||||
@@ -20,26 +21,25 @@ namespace JT809.DotNetty.Core.Handlers | |||||
{ | { | ||||
protected JT809Configuration Configuration { get; } | protected JT809Configuration Configuration { get; } | ||||
protected ILogger Logger { get; } | protected ILogger Logger { get; } | ||||
protected IJT809ManualResetEvent ManualResetEvent { get; } | |||||
/// <summary> | /// <summary> | ||||
/// 初始化消息处理业务 | /// 初始化消息处理业务 | ||||
/// </summary> | /// </summary> | ||||
protected JT809InferiorMsgIdReceiveHandlerBase( | protected JT809InferiorMsgIdReceiveHandlerBase( | ||||
ILoggerFactory loggerFactory, | |||||
IOptions<JT809Configuration> jT809ConfigurationAccessor, | |||||
IJT809VerifyCodeGenerator verifyCodeGenerator, | |||||
JT809SubordinateClient subordinateLinkClient) | |||||
IJT809ManualResetEvent jT809ManualResetEvent, | |||||
ILoggerFactory loggerFactory) | |||||
{ | { | ||||
this.Logger = loggerFactory.CreateLogger<JT809SuperiorMsgIdReceiveHandlerBase>(); | this.Logger = loggerFactory.CreateLogger<JT809SuperiorMsgIdReceiveHandlerBase>(); | ||||
this.ManualResetEvent = jT809ManualResetEvent; | |||||
HandlerDict = new Dictionary<JT809BusinessType, Func<JT809Request, JT809Response>> | HandlerDict = new Dictionary<JT809BusinessType, Func<JT809Request, JT809Response>> | ||||
{ | { | ||||
//{JT809BusinessType.主链路登录请求消息, Msg0x1001}, | |||||
{JT809BusinessType.主链路注销请求消息, Msg0x1003}, | |||||
{JT809BusinessType.主链路连接保持请求消息, Msg0x1005}, | |||||
{JT809BusinessType.主链路动态信息交换消息, Msg0x1200}, | |||||
{JT809BusinessType.从链路注销应答消息, Msg0x9004}, | |||||
{JT809BusinessType.主链路登录应答消息,Msg0x1002}, | |||||
{JT809BusinessType.主链路连接保持应答消息,Msg0x1006}, | |||||
{JT809BusinessType.从链路连接请求消息,Msg0x9001}, | |||||
{JT809BusinessType.从链路注销请求消息, Msg0x9003}, | |||||
{JT809BusinessType.从链路连接保持请求消息,Msg0x9005 }, | |||||
}; | }; | ||||
SubHandlerDict = new Dictionary<JT809SubBusinessType, Func<JT809Request, JT809Response>> | SubHandlerDict = new Dictionary<JT809SubBusinessType, Func<JT809Request, JT809Response>> | ||||
{ | { | ||||
//{JT809SubBusinessType.实时上传车辆定位信息, Msg0x1200_0x1202}, | //{JT809SubBusinessType.实时上传车辆定位信息, Msg0x1200_0x1202}, | ||||
@@ -50,69 +50,83 @@ namespace JT809.DotNetty.Core.Handlers | |||||
public Dictionary<JT809SubBusinessType, Func<JT809Request, JT809Response>> SubHandlerDict { get; protected set; } | public Dictionary<JT809SubBusinessType, Func<JT809Request, JT809Response>> SubHandlerDict { get; protected set; } | ||||
/// <summary> | /// <summary> | ||||
/// 主链路登录请求消息 | |||||
/// 主链路登录应答消息 | |||||
/// </summary> | /// </summary> | ||||
/// <param name="request"></param> | /// <param name="request"></param> | ||||
/// <returns>主链路登录应答消息</returns> | |||||
//public virtual JT809Response Msg0x1001(JT809Request request) | |||||
//{ | |||||
// var verifyCode = VerifyCodeGenerator.Create(); | |||||
// Logger.LogInformation($"VerifyCode-{verifyCode}"); | |||||
// var package = JT809BusinessType.主链路登录应答消息.Create(new JT809_0x1002() | |||||
// { | |||||
// Result = JT809_0x1002_Result.成功, | |||||
// VerifyCode = verifyCode | |||||
// }); | |||||
// if (Configuration.SubordinateClientEnable) | |||||
// { | |||||
// var jT809_0x1001 = request.Package.Bodies as JT809_0x1001; | |||||
// SubordinateLinkClient.ConnectAsync(jT809_0x1001.DownLinkIP, jT809_0x1001.DownLinkPort, verifyCode); | |||||
// } | |||||
// return new JT809Response(package, 100); | |||||
//} | |||||
/// <returns></returns> | |||||
public virtual JT809Response Msg0x1002(JT809Request request) | |||||
{ | |||||
if (Logger.IsEnabled(LogLevel.Information)) | |||||
{ | |||||
Logger.LogInformation(JsonConvert.SerializeObject(request)); | |||||
} | |||||
var jT809_0x1002 = request.Package.Bodies as JT809_0x1002; | |||||
if(jT809_0x1002.Result== JT809_0x1002_Result.成功) | |||||
{ | |||||
ManualResetEvent.Resume(); | |||||
} | |||||
return null; | |||||
} | |||||
/// <summary> | /// <summary> | ||||
/// 主链路注销请求消息 | |||||
/// 主链路连接保持应答消息 | |||||
/// </summary> | /// </summary> | ||||
/// <param name="request"></param> | /// <param name="request"></param> | ||||
/// <returns>主链路注销应答消息</returns> | |||||
public virtual JT809Response Msg0x1003(JT809Request request) | |||||
/// <returns></returns> | |||||
public virtual JT809Response Msg0x1006(JT809Request request) | |||||
{ | { | ||||
var package = JT809BusinessType.主链路注销应答消息.Create(); | |||||
return new JT809Response(package, 100); | |||||
if (Logger.IsEnabled(LogLevel.Information)) | |||||
{ | |||||
Logger.LogInformation(JsonConvert.SerializeObject(request)); | |||||
} | |||||
return null; | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
/// 主链路连接保持请求消息 | |||||
/// 从链路连接请求消息 | |||||
/// </summary> | /// </summary> | ||||
/// <param name="request"></param> | /// <param name="request"></param> | ||||
/// <returns>主链路连接保持应答消息</returns> | |||||
public virtual JT809Response Msg0x1005(JT809Request request) | |||||
/// <returns>从链路连接应答消息</returns> | |||||
public virtual JT809Response Msg0x9001(JT809Request request) | |||||
{ | { | ||||
var package = JT809BusinessType.主链路连接保持应答消息.Create(); | |||||
var package = JT809BusinessType.从链路连接应答消息.Create(new JT809_0x9002 { | |||||
Result = JT809_0x9002_Result.成功 | |||||
}); | |||||
if (Logger.IsEnabled(LogLevel.Information)) | |||||
{ | |||||
Logger.LogInformation(JsonConvert.SerializeObject(request)); | |||||
} | |||||
return new JT809Response(package, 100); | return new JT809Response(package, 100); | ||||
} | } | ||||
/// <summary> | /// <summary> | ||||
/// 主链路动态信息交换消息 | |||||
/// 从链路注销请求消息 | |||||
/// </summary> | /// </summary> | ||||
/// <param name="request"></param> | /// <param name="request"></param> | ||||
/// <returns></returns> | |||||
public virtual JT809Response Msg0x1200(JT809Request request) | |||||
/// <returns>从链路注销应答消息</returns> | |||||
public virtual JT809Response Msg0x9003(JT809Request request) | |||||
{ | { | ||||
return null; | |||||
var package = JT809BusinessType.从链路注销应答消息.Create(); | |||||
if (Logger.IsEnabled(LogLevel.Information)) | |||||
{ | |||||
Logger.LogInformation(JsonConvert.SerializeObject(request)); | |||||
} | |||||
return new JT809Response(package, 100); | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
/// | |||||
/// 从链路连接保持请求消息 | |||||
/// </summary> | /// </summary> | ||||
/// <param name="request"></param> | /// <param name="request"></param> | ||||
/// <returns>从链路注销应答消息</returns> | |||||
public virtual JT809Response Msg0x9004(JT809Request request) | |||||
/// <returns>从链路连接保持应答消息</returns> | |||||
public virtual JT809Response Msg0x9005(JT809Request request) | |||||
{ | { | ||||
return null; | |||||
var package = JT809BusinessType.从链路连接保持应答消息.Create(); | |||||
if (Logger.IsEnabled(LogLevel.Information)) | |||||
{ | |||||
Logger.LogInformation(JsonConvert.SerializeObject(request)); | |||||
} | |||||
return new JT809Response(package, 100); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -16,7 +16,6 @@ namespace JT809.DotNetty.Core.Handlers | |||||
private readonly ILogger<JT809SubordinateServerConnectionHandler> logger; | private readonly ILogger<JT809SubordinateServerConnectionHandler> logger; | ||||
public JT809SubordinateServerConnectionHandler( | public JT809SubordinateServerConnectionHandler( | ||||
JT809SubordinateClient subordinateClient, | |||||
ILoggerFactory loggerFactory) | ILoggerFactory loggerFactory) | ||||
{ | { | ||||
logger = loggerFactory.CreateLogger<JT809SubordinateServerConnectionHandler>(); | logger = loggerFactory.CreateLogger<JT809SubordinateServerConnectionHandler>(); | ||||
@@ -73,10 +72,7 @@ namespace JT809.DotNetty.Core.Handlers | |||||
{ | { | ||||
if (idleStateEvent.State == IdleState.ReaderIdle) | if (idleStateEvent.State == IdleState.ReaderIdle) | ||||
{ | { | ||||
if (idleStateEvent.State == IdleState.ReaderIdle) | |||||
{ | |||||
context.CloseAsync(); | |||||
} | |||||
context.CloseAsync(); | |||||
} | } | ||||
} | } | ||||
base.UserEventTriggered(context, evt); | base.UserEventTriggered(context, evt); | ||||
@@ -0,0 +1,13 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace JT809.DotNetty.Core.Interfaces | |||||
{ | |||||
public interface IJT809ManualResetEvent | |||||
{ | |||||
void Pause(); | |||||
bool Resume(); | |||||
bool Reset(); | |||||
} | |||||
} |
@@ -17,7 +17,7 @@ namespace JT809.DotNetty.Core.Internal | |||||
/// </summary> | /// </summary> | ||||
internal class JT809InferiorMsgIdReceiveDefaultHandler : JT809InferiorMsgIdReceiveHandlerBase | internal class JT809InferiorMsgIdReceiveDefaultHandler : JT809InferiorMsgIdReceiveHandlerBase | ||||
{ | { | ||||
public JT809InferiorMsgIdReceiveDefaultHandler(ILoggerFactory loggerFactory, IOptions<JT809Configuration> jT809ConfigurationAccessor, IJT809VerifyCodeGenerator verifyCodeGenerator, JT809SubordinateClient subordinateLinkClient) : base(loggerFactory, jT809ConfigurationAccessor, verifyCodeGenerator, subordinateLinkClient) | |||||
public JT809InferiorMsgIdReceiveDefaultHandler(IJT809ManualResetEvent jT809ManualResetEvent, ILoggerFactory loggerFactory) : base(jT809ManualResetEvent, loggerFactory) | |||||
{ | { | ||||
} | } | ||||
} | } | ||||
@@ -19,6 +19,7 @@ using System.Runtime.CompilerServices; | |||||
using Microsoft.Extensions.Options; | using Microsoft.Extensions.Options; | ||||
using JT808.DotNetty.WebApi; | using JT808.DotNetty.WebApi; | ||||
using JT809.DotNetty.Core.Session; | using JT809.DotNetty.Core.Session; | ||||
using JT809.DotNetty.Core.Events; | |||||
[assembly: InternalsVisibleTo("JT809.DotNetty.Core.Test")] | [assembly: InternalsVisibleTo("JT809.DotNetty.Core.Test")] | ||||
@@ -83,15 +84,35 @@ namespace JT809.DotNetty.Core | |||||
//主从链路接收消息默认业务处理器 | //主从链路接收消息默认业务处理器 | ||||
serviceDescriptors.TryAddSingleton<JT809InferiorMsgIdReceiveHandlerBase, JT809InferiorMsgIdReceiveDefaultHandler>(); | serviceDescriptors.TryAddSingleton<JT809InferiorMsgIdReceiveHandlerBase, JT809InferiorMsgIdReceiveDefaultHandler>(); | ||||
//主从链路消息接收处理器 | //主从链路消息接收处理器 | ||||
serviceDescriptors.TryAddScoped<JT809MainServerHandler>(); | |||||
serviceDescriptors.TryAddScoped<JT809SubordinateServerHandler>(); | serviceDescriptors.TryAddScoped<JT809SubordinateServerHandler>(); | ||||
//主链路客户端 | //主链路客户端 | ||||
serviceDescriptors.TryAddSingleton<JT809MainClient>(); | |||||
//serviceDescriptors.TryAddSingleton<JT809MainClient>(); | |||||
//从链路服务端 | //从链路服务端 | ||||
serviceDescriptors.AddHostedService<JT809SubordinateServerHost>(); | serviceDescriptors.AddHostedService<JT809SubordinateServerHost>(); | ||||
return serviceDescriptors; | return serviceDescriptors; | ||||
} | } | ||||
/// <summary> | |||||
/// 下级平台 | |||||
/// 主链路为客户端 | |||||
/// 从链路为服务端 | |||||
/// </summary> | |||||
/// <param name="serviceDescriptors"></param> | |||||
/// <returns></returns> | |||||
public static IServiceCollection AddJT809InferiorPlatformClient(this IServiceCollection serviceDescriptors) | |||||
{ | |||||
serviceDescriptors.TryAddSingleton<IJT809ManualResetEvent, JT809InferoprManualResetEvent>(); | |||||
//主从链路客户端和服务端连接处理器 | |||||
serviceDescriptors.TryAddScoped<JT809MainClientConnectionHandler>(); | |||||
//主从链路接收消息默认业务处理器 | |||||
serviceDescriptors.TryAddSingleton<JT809InferiorMsgIdReceiveHandlerBase, JT809InferiorMsgIdReceiveDefaultHandler>(); | |||||
//主从链路消息接收处理器 | |||||
serviceDescriptors.TryAddScoped<JT809MainClientHandler>(); | |||||
//主链路客户端 | |||||
serviceDescriptors.TryAddSingleton<JT809MainClient>(); | |||||
return serviceDescriptors; | |||||
} | |||||
/// <summary> | /// <summary> | ||||
/// 上级平台 | /// 上级平台 | ||||
@@ -33,7 +33,6 @@ namespace JT809.DotNetty.Core.Servers | |||||
private WorkerEventLoopGroup workerGroup; | private WorkerEventLoopGroup workerGroup; | ||||
private IChannel bootstrapChannel; | private IChannel bootstrapChannel; | ||||
private IByteBufferAllocator serverBufferAllocator; | private IByteBufferAllocator serverBufferAllocator; | ||||
private ILoggerFactory loggerFactory; | |||||
public JT809SubordinateServerHost( | public JT809SubordinateServerHost( | ||||
IServiceProvider provider, | IServiceProvider provider, | ||||
@@ -43,7 +42,6 @@ namespace JT809.DotNetty.Core.Servers | |||||
serviceProvider = provider; | serviceProvider = provider; | ||||
configuration = jT809ConfigurationAccessor.Value; | configuration = jT809ConfigurationAccessor.Value; | ||||
logger = loggerFactory.CreateLogger<JT809SubordinateServerHost>(); | logger = loggerFactory.CreateLogger<JT809SubordinateServerHost>(); | ||||
this.loggerFactory = loggerFactory; | |||||
} | } | ||||
public Task StartAsync(CancellationToken cancellationToken) | public Task StartAsync(CancellationToken cancellationToken) | ||||
@@ -0,0 +1,24 @@ | |||||
<Project Sdk="Microsoft.NET.Sdk"> | |||||
<PropertyGroup> | |||||
<OutputType>Exe</OutputType> | |||||
<TargetFramework>netcoreapp2.2</TargetFramework> | |||||
<LangVersion>7.3</LangVersion> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<PackageReference Include="JT809.Extensions.DependencyInjection" Version="1.2.1" /> | |||||
<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.Core\JT809.DotNetty.Core.csproj" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<None Update="appsettings.json"> | |||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | |||||
</None> | |||||
</ItemGroup> | |||||
</Project> |
@@ -0,0 +1,119 @@ | |||||
using JT809.DotNetty.Core.Clients; | |||||
using JT809.DotNetty.Core.Metadata; | |||||
using JT809.Protocol.Extensions; | |||||
using Microsoft.Extensions.Hosting; | |||||
using Microsoft.Extensions.Logging; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using System.Threading; | |||||
using System.Threading.Tasks; | |||||
using JT809.Protocol.SubMessageBody; | |||||
using JT809.Protocol.Metadata; | |||||
using JT809.Protocol.MessageBody; | |||||
namespace JT809.Inferior.Client | |||||
{ | |||||
public class JT809InferiorService : IHostedService | |||||
{ | |||||
private readonly JT809MainClient mainClient; | |||||
private readonly ILogger<JT809InferiorService> logger; | |||||
public JT809InferiorService( | |||||
ILoggerFactory loggerFactory, | |||||
JT809MainClient mainClient) | |||||
{ | |||||
this.mainClient = mainClient; | |||||
logger = loggerFactory.CreateLogger<JT809InferiorService>(); | |||||
} | |||||
public Task StartAsync(CancellationToken cancellationToken) | |||||
{ | |||||
//5B0000001F0000053B100201341725010000000000270F00000004E8A6F25D | |||||
var connect = mainClient.Login("127.0.0.1", 809, new JT809_0x1001 | |||||
{ | |||||
DownLinkIP = "127.0.0.1", | |||||
DownLinkPort = 1809, | |||||
UserId = 123456, | |||||
Password = "12345678" | |||||
}).Result; | |||||
if (connect) | |||||
{ | |||||
Task.Run(() => | |||||
{ | |||||
while (true) | |||||
{ | |||||
JT809.Protocol.MessageBody.JT809_0x1200 jT809_0X1200 = new Protocol.MessageBody.JT809_0x1200(); | |||||
jT809_0X1200.VehicleColor = Protocol.Enums.JT809VehicleColorType.黄色; | |||||
jT809_0X1200.VehicleNo = "粤A12345"; | |||||
jT809_0X1200.SubBusinessType = Protocol.Enums.JT809SubBusinessType.实时上传车辆定位信息; | |||||
jT809_0X1200.SubBodies = new JT809_0x1200_0x1202() | |||||
{ | |||||
VehiclePosition = new JT809VehiclePositionProperties | |||||
{ | |||||
Day = (byte)(DateTime.Now.Day), | |||||
Month = (byte)(DateTime.Now.Month), | |||||
Year = (byte)(DateTime.Now.Year), | |||||
Hour = (byte)(DateTime.Now.Hour), | |||||
Minute = (byte)(DateTime.Now.Minute), | |||||
Second = (byte)(DateTime.Now.Second), | |||||
Alarm = 1, | |||||
Direction = 2, | |||||
State = 2, | |||||
Altitude = 32, | |||||
Lat = 122334565, | |||||
Lon = 12354563, | |||||
Vec1 = 112, | |||||
Vec2 = 22, | |||||
Vec3 = 12 | |||||
} | |||||
}; | |||||
var package = JT809.Protocol.Enums.JT809BusinessType.主链路动态信息交换消息.Create(jT809_0X1200); | |||||
mainClient.SendAsync(new JT809Response(package, 256)); | |||||
logger.LogDebug($"Thread:{Thread.CurrentThread.ManagedThreadId}-2s"); | |||||
Thread.Sleep(2000); | |||||
} | |||||
}); | |||||
Task.Run(() => | |||||
{ | |||||
while (true) | |||||
{ | |||||
JT809.Protocol.MessageBody.JT809_0x1200 jT809_0X1200 = new Protocol.MessageBody.JT809_0x1200(); | |||||
jT809_0X1200.VehicleColor = Protocol.Enums.JT809VehicleColorType.黄色; | |||||
jT809_0X1200.VehicleNo = "粤A12346"; | |||||
jT809_0X1200.SubBusinessType = Protocol.Enums.JT809SubBusinessType.实时上传车辆定位信息; | |||||
jT809_0X1200.SubBodies = new JT809_0x1200_0x1202() | |||||
{ | |||||
VehiclePosition = new JT809VehiclePositionProperties | |||||
{ | |||||
Day = (byte)(DateTime.Now.Day), | |||||
Month = (byte)(DateTime.Now.Month), | |||||
Year = (byte)(DateTime.Now.Year), | |||||
Hour = (byte)(DateTime.Now.Hour), | |||||
Minute = (byte)(DateTime.Now.Minute), | |||||
Second = (byte)(DateTime.Now.Second), | |||||
Alarm = 1, | |||||
Direction = 2, | |||||
State = 2, | |||||
Altitude = 32, | |||||
Lat = 122334565, | |||||
Lon = 12354563, | |||||
Vec1 = 112, | |||||
Vec2 = 22, | |||||
Vec3 = 12 | |||||
} | |||||
}; | |||||
var package = JT809.Protocol.Enums.JT809BusinessType.主链路动态信息交换消息.Create(jT809_0X1200); | |||||
mainClient.SendAsync(new JT809Response(package, 256)); | |||||
logger.LogDebug($"Thread:{Thread.CurrentThread.ManagedThreadId}-4s"); | |||||
Thread.Sleep(4000); | |||||
} | |||||
}); | |||||
} | |||||
return Task.CompletedTask; | |||||
} | |||||
public Task StopAsync(CancellationToken cancellationToken) | |||||
{ | |||||
return Task.CompletedTask; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,48 @@ | |||||
using JT809.DotNetty.Core; | |||||
using JT809.DotNetty.Core.Handlers; | |||||
using Microsoft.Extensions.Configuration; | |||||
using Microsoft.Extensions.DependencyInjection; | |||||
using Microsoft.Extensions.DependencyInjection.Extensions; | |||||
using Microsoft.Extensions.Hosting; | |||||
using Microsoft.Extensions.Logging; | |||||
using System; | |||||
using System.Threading.Tasks; | |||||
using JT809.Protocol.Extensions.DependencyInjection; | |||||
using JT809.Protocol.Extensions.DependencyInjection.Options; | |||||
namespace JT809.Inferior.Client | |||||
{ | |||||
class Program | |||||
{ | |||||
static async Task Main(string[] args) | |||||
{ | |||||
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.AddJT809Configure(new JT809Options | |||||
{ | |||||
HeaderOptions = new Protocol.Configs.JT809HeaderOptions | |||||
{ | |||||
MsgGNSSCENTERID = 100210, | |||||
} | |||||
}); | |||||
services.AddJT809Core(hostContext.Configuration) | |||||
.AddJT809InferiorPlatformClient(); | |||||
services.AddHostedService<JT809InferiorService>(); | |||||
}); | |||||
await serverHostBuilder.RunConsoleAsync(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,15 @@ | |||||
{ | |||||
"Logging": { | |||||
"IncludeScopes": false, | |||||
"Debug": { | |||||
"LogLevel": { | |||||
"Default": "Trace" | |||||
} | |||||
}, | |||||
"Console": { | |||||
"LogLevel": { | |||||
"Default": "Trace" | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,24 @@ | |||||
<Project Sdk="Microsoft.NET.Sdk"> | |||||
<PropertyGroup> | |||||
<OutputType>Exe</OutputType> | |||||
<TargetFramework>netcoreapp2.2</TargetFramework> | |||||
<LangVersion>7.3</LangVersion> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<PackageReference Include="JT809.Extensions.DependencyInjection" Version="1.2.1" /> | |||||
<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.Core\JT809.DotNetty.Core.csproj" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<None Update="appsettings.json"> | |||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | |||||
</None> | |||||
</ItemGroup> | |||||
</Project> |
@@ -0,0 +1,55 @@ | |||||
using JT809.DotNetty.Core; | |||||
using JT809.DotNetty.Core.Handlers; | |||||
using Microsoft.Extensions.Configuration; | |||||
using Microsoft.Extensions.DependencyInjection; | |||||
using Microsoft.Extensions.DependencyInjection.Extensions; | |||||
using Microsoft.Extensions.Hosting; | |||||
using Microsoft.Extensions.Logging; | |||||
using System; | |||||
using System.Threading.Tasks; | |||||
using JT809.Protocol.Extensions.DependencyInjection; | |||||
using JT809.Protocol.Extensions.DependencyInjection.Options; | |||||
namespace JT809.Inferior.Server | |||||
{ | |||||
class Program | |||||
{ | |||||
static async Task Main(string[] args) | |||||
{ | |||||
//作为从链路服务器,接收上级平台连接请求包括 | |||||
//1.从链路连接请求消息-从链路连接应答消息 | |||||
//5B 00 00 00 1B 00 00 00 02 90 02 00 01 87 72 01 00 00 00 00 00 00 00 00 AB 10 5D | |||||
//2.从链路连接保持请求消息-从链路连接保持应答消息 | |||||
//5B 00 00 00 1A 00 00 00 03 90 06 00 01 87 72 01 00 00 00 00 00 00 00 64 E7 5D | |||||
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.AddJT809Configure(new JT809Options | |||||
{ | |||||
HeaderOptions=new Protocol.Configs.JT809HeaderOptions | |||||
{ | |||||
MsgGNSSCENTERID=100210 | |||||
} | |||||
}); | |||||
services.AddJT809Core(hostContext.Configuration) | |||||
.AddJT809InferiorPlatform(options: options => { | |||||
options.TcpPort = 809; | |||||
}); | |||||
}); | |||||
await serverHostBuilder.RunConsoleAsync(); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,15 @@ | |||||
{ | |||||
"Logging": { | |||||
"IncludeScopes": false, | |||||
"Debug": { | |||||
"LogLevel": { | |||||
"Default": "Trace" | |||||
} | |||||
}, | |||||
"Console": { | |||||
"LogLevel": { | |||||
"Default": "Trace" | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -27,9 +27,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT809.KafkaService", "JT809 | |||||
EndProject | EndProject | ||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT809.KafkaServiceTest", "JT809.DotNetty.Simples\Superior\JT809.KafkaServiceTest\JT809.KafkaServiceTest.csproj", "{22F008D5-61F8-4889-80DB-91B37591322F}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT809.KafkaServiceTest", "JT809.DotNetty.Simples\Superior\JT809.KafkaServiceTest\JT809.KafkaServiceTest.csproj", "{22F008D5-61F8-4889-80DB-91B37591322F}" | ||||
EndProject | EndProject | ||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT809.Superior.Server", "JT809.DotNetty.Simples\Superior\JT809.Superior.Server\JT809.Superior.Server.csproj", "{8620735D-FBD5-4832-882F-A2F607DC6861}" | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT809.Superior.Server", "JT809.DotNetty.Simples\Superior\JT809.Superior.Server\JT809.Superior.Server.csproj", "{8620735D-FBD5-4832-882F-A2F607DC6861}" | |||||
EndProject | EndProject | ||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT809.GpsConsumer", "JT809.DotNetty.Simples\Superior\JT809.GpsConsumer\JT809.GpsConsumer.csproj", "{FBC06008-6F18-4CC3-B7C2-5B476317F92D}" | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT809.GpsConsumer", "JT809.DotNetty.Simples\Superior\JT809.GpsConsumer\JT809.GpsConsumer.csproj", "{FBC06008-6F18-4CC3-B7C2-5B476317F92D}" | |||||
EndProject | |||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Inferior", "Inferior", "{139F3035-EAC2-42A8-9123-1F7E6B79AFEB}" | |||||
EndProject | |||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT809.Inferior.Server", "JT809.DotNetty.Simples\Inferior\JT809.Inferior.Server\JT809.Inferior.Server.csproj", "{126FFC37-3ABF-4537-A0DD-3FC609F853EF}" | |||||
EndProject | |||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT809.Inferior.Client", "JT809.DotNetty.Simples\Inferior\JT809.Inferior.Client\JT809.Inferior.Client.csproj", "{5990307A-4EE9-40B7-80E8-5AE2E7697287}" | |||||
EndProject | EndProject | ||||
Global | Global | ||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||
@@ -77,6 +83,14 @@ Global | |||||
{FBC06008-6F18-4CC3-B7C2-5B476317F92D}.Debug|Any CPU.Build.0 = Debug|Any CPU | {FBC06008-6F18-4CC3-B7C2-5B476317F92D}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
{FBC06008-6F18-4CC3-B7C2-5B476317F92D}.Release|Any CPU.ActiveCfg = Release|Any CPU | {FBC06008-6F18-4CC3-B7C2-5B476317F92D}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
{FBC06008-6F18-4CC3-B7C2-5B476317F92D}.Release|Any CPU.Build.0 = Release|Any CPU | {FBC06008-6F18-4CC3-B7C2-5B476317F92D}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
{126FFC37-3ABF-4537-A0DD-3FC609F853EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{126FFC37-3ABF-4537-A0DD-3FC609F853EF}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{126FFC37-3ABF-4537-A0DD-3FC609F853EF}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{126FFC37-3ABF-4537-A0DD-3FC609F853EF}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{5990307A-4EE9-40B7-80E8-5AE2E7697287}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{5990307A-4EE9-40B7-80E8-5AE2E7697287}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{5990307A-4EE9-40B7-80E8-5AE2E7697287}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{5990307A-4EE9-40B7-80E8-5AE2E7697287}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
EndGlobalSection | EndGlobalSection | ||||
GlobalSection(SolutionProperties) = preSolution | GlobalSection(SolutionProperties) = preSolution | ||||
HideSolutionNode = FALSE | HideSolutionNode = FALSE | ||||
@@ -91,6 +105,9 @@ Global | |||||
{22F008D5-61F8-4889-80DB-91B37591322F} = {E9DC871D-EFCE-4D53-A5B5-8A88D2D52EA4} | {22F008D5-61F8-4889-80DB-91B37591322F} = {E9DC871D-EFCE-4D53-A5B5-8A88D2D52EA4} | ||||
{8620735D-FBD5-4832-882F-A2F607DC6861} = {E9DC871D-EFCE-4D53-A5B5-8A88D2D52EA4} | {8620735D-FBD5-4832-882F-A2F607DC6861} = {E9DC871D-EFCE-4D53-A5B5-8A88D2D52EA4} | ||||
{FBC06008-6F18-4CC3-B7C2-5B476317F92D} = {E9DC871D-EFCE-4D53-A5B5-8A88D2D52EA4} | {FBC06008-6F18-4CC3-B7C2-5B476317F92D} = {E9DC871D-EFCE-4D53-A5B5-8A88D2D52EA4} | ||||
{139F3035-EAC2-42A8-9123-1F7E6B79AFEB} = {3C761892-4ED8-42D2-96CF-F76041D17EC1} | |||||
{126FFC37-3ABF-4537-A0DD-3FC609F853EF} = {139F3035-EAC2-42A8-9123-1F7E6B79AFEB} | |||||
{5990307A-4EE9-40B7-80E8-5AE2E7697287} = {139F3035-EAC2-42A8-9123-1F7E6B79AFEB} | |||||
EndGlobalSection | EndGlobalSection | ||||
GlobalSection(ExtensibilityGlobals) = postSolution | GlobalSection(ExtensibilityGlobals) = postSolution | ||||
SolutionGuid = {0FC2A52E-3B7A-4485-9C3B-9080C825419D} | SolutionGuid = {0FC2A52E-3B7A-4485-9C3B-9080C825419D} | ||||