@@ -0,0 +1,20 @@ | |||||
using DotNetty.Buffers; | |||||
using DotNetty.Codecs; | |||||
using System.Collections.Generic; | |||||
using JT808.Protocol; | |||||
using DotNetty.Transport.Channels; | |||||
namespace JT808.DotNetty.Client.Codecs | |||||
{ | |||||
public class JT808ClientTcpDecoder : 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] = JT808Package.BeginFlag; | |||||
buffer[input.Capacity + 1] = JT808Package.EndFlag; | |||||
output.Add(buffer); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,44 @@ | |||||
using DotNetty.Buffers; | |||||
using DotNetty.Codecs; | |||||
using System.Collections.Generic; | |||||
using JT808.Protocol; | |||||
using DotNetty.Transport.Channels; | |||||
using Microsoft.Extensions.Logging; | |||||
using JT808.DotNetty.Client.Metadata; | |||||
namespace JT808.DotNetty.Client.Codecs | |||||
{ | |||||
public class JT808ClientTcpEncoder : MessageToByteEncoder<JT808ClientRequest> | |||||
{ | |||||
private readonly ILogger<JT808ClientTcpEncoder> logger; | |||||
public JT808ClientTcpEncoder(ILoggerFactory loggerFactory) | |||||
{ | |||||
logger=loggerFactory.CreateLogger<JT808ClientTcpEncoder>(); | |||||
} | |||||
protected override void Encode(IChannelHandlerContext context, JT808ClientRequest message, IByteBuffer output) | |||||
{ | |||||
if (message.Package != null) | |||||
{ | |||||
try | |||||
{ | |||||
var sendData = JT808Serializer.Serialize(message.Package, message.MinBufferSize); | |||||
output.WriteBytes(sendData); | |||||
} | |||||
catch (JT808.Protocol.Exceptions.JT808Exception ex) | |||||
{ | |||||
logger.LogError(ex, context.Channel.Id.AsShortText()); | |||||
} | |||||
catch (System.Exception ex) | |||||
{ | |||||
logger.LogError(ex, context.Channel.Id.AsShortText()); | |||||
} | |||||
} | |||||
else if (message.HexData != null) | |||||
{ | |||||
output.WriteBytes(message.HexData); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,27 @@ | |||||
using JT808.Protocol; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace JT808.DotNetty.Client | |||||
{ | |||||
public class DeviceConfig | |||||
{ | |||||
public DeviceConfig(string terminalPhoneNo, string tcpHost,int tcpPort) | |||||
{ | |||||
TerminalPhoneNo = terminalPhoneNo; | |||||
TcpHost = tcpHost; | |||||
TcpPort = tcpPort; | |||||
MsgSNDistributed = new JT808ClientMsgSNDistributedImpl(); | |||||
} | |||||
public string TerminalPhoneNo { get; private set; } | |||||
public string TcpHost { get; private set; } | |||||
public int TcpPort { get; private set; } | |||||
/// <summary> | |||||
/// 心跳时间(秒) | |||||
/// </summary> | |||||
public int Heartbeat { get; set; } = 30; | |||||
public IMsgSNDistributed MsgSNDistributed { get; } | |||||
} | |||||
} |
@@ -0,0 +1,95 @@ | |||||
using DotNetty.Handlers.Timeout; | |||||
using DotNetty.Transport.Channels; | |||||
using JT808.Protocol.MessageBody; | |||||
using Microsoft.Extensions.Logging; | |||||
using System; | |||||
using System.Threading.Tasks; | |||||
namespace JT808.DotNetty.Client.Handlers | |||||
{ | |||||
/// <summary> | |||||
/// JT808客户端连接通道处理程序 | |||||
/// </summary> | |||||
public class JT808TcpClientConnectionHandler : ChannelHandlerAdapter | |||||
{ | |||||
private readonly ILogger<JT808TcpClientConnectionHandler> logger; | |||||
private readonly JT808TcpClient jT808TcpClient; | |||||
public JT808TcpClientConnectionHandler( | |||||
JT808TcpClient jT808TcpClient) | |||||
{ | |||||
logger = jT808TcpClient.LoggerFactory.CreateLogger<JT808TcpClientConnectionHandler>(); | |||||
this.jT808TcpClient = jT808TcpClient; | |||||
} | |||||
/// <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."); | |||||
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."); | |||||
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.WriterIdle) | |||||
{ | |||||
string channelId = context.Channel.Id.AsShortText(); | |||||
logger.LogInformation($"{idleStateEvent.State.ToString()}>>>{channelId}"); | |||||
jT808TcpClient.Send(new JT808_0x0002()); | |||||
} | |||||
} | |||||
base.UserEventTriggered(context, evt); | |||||
} | |||||
public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) | |||||
{ | |||||
string channelId = context.Channel.Id.AsShortText(); | |||||
logger.LogError(exception,$"{channelId} {exception.Message}" ); | |||||
context.CloseAsync(); | |||||
} | |||||
} | |||||
} | |||||
@@ -0,0 +1,27 @@ | |||||
using DotNetty.Buffers; | |||||
using DotNetty.Transport.Channels; | |||||
using System; | |||||
using Microsoft.Extensions.Logging; | |||||
using Microsoft.Extensions.DependencyInjection; | |||||
namespace JT808.DotNetty.Client.Handlers | |||||
{ | |||||
/// <summary> | |||||
/// JT808客户端处理程序 | |||||
/// </summary> | |||||
internal class JT808TcpClientHandler : SimpleChannelInboundHandler<byte[]> | |||||
{ | |||||
private readonly ILogger<JT808TcpClientHandler> logger; | |||||
public JT808TcpClientHandler(JT808TcpClient jT808TcpClient) | |||||
{ | |||||
logger = jT808TcpClient.LoggerFactory.CreateLogger<JT808TcpClientHandler>(); | |||||
} | |||||
protected override void ChannelRead0(IChannelHandlerContext ctx, byte[] msg) | |||||
{ | |||||
if(logger.IsEnabled(LogLevel.Debug)) | |||||
logger.LogDebug("accept msg<<<" + ByteBufferUtil.HexDump(msg)); | |||||
} | |||||
} | |||||
} |
@@ -1,11 +1,34 @@ | |||||
<Project Sdk="Microsoft.NET.Sdk"> | |||||
<Project Sdk="Microsoft.NET.Sdk"> | |||||
<PropertyGroup> | <PropertyGroup> | ||||
<TargetFramework>netstandard2.0</TargetFramework> | <TargetFramework>netstandard2.0</TargetFramework> | ||||
<LangVersion>7.1</LangVersion> | |||||
<Copyright>Copyright 2018.</Copyright> | |||||
<Authors>SmallChi</Authors> | |||||
<PackageId>JT808.DotNetty.Client</PackageId> | |||||
<Product>JT808.DotNetty.Client</Product> | |||||
<Description>基于DotNetty实现的JT808DotNetty的客户端工具</Description> | |||||
<PackageReleaseNotes>基于DotNetty实现的JT808DotNetty的客户端工具</PackageReleaseNotes> | |||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance> | |||||
<RepositoryUrl>https://github.com/SmallChi/JT808DotNetty</RepositoryUrl> | |||||
<PackageProjectUrl>https://github.com/SmallChi/JT808DotNetty</PackageProjectUrl> | |||||
<PackageLicenseUrl>https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE</PackageLicenseUrl> | |||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> | |||||
<Version>1.1.1</Version> | |||||
</PropertyGroup> | </PropertyGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<ProjectReference Include="..\JT808.DotNetty.Core\JT808.DotNetty.Core.csproj" /> | |||||
<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="..\JT808.Protocol\src\JT808.Protocol\JT808.Protocol.csproj" /> | |||||
</ItemGroup> | </ItemGroup> | ||||
</Project> | </Project> |
@@ -0,0 +1,16 @@ | |||||
using Microsoft.Extensions.DependencyInjection; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace JT808.DotNetty.Client | |||||
{ | |||||
public static class JT808ClientDotnettyExtensions | |||||
{ | |||||
public static IServiceCollection AddJT808Client(this IServiceCollection serviceDescriptors) | |||||
{ | |||||
serviceDescriptors.AddSingleton<IJT808TcpClientFactory, JT808TcpClientFactory>(); | |||||
return serviceDescriptors; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,15 @@ | |||||
using JT808.Protocol; | |||||
using System.Threading; | |||||
namespace JT808.DotNetty.Client | |||||
{ | |||||
internal class JT808ClientMsgSNDistributedImpl : IMsgSNDistributed | |||||
{ | |||||
int _counter = 0; | |||||
public ushort Increment() | |||||
{ | |||||
return (ushort)Interlocked.Increment(ref _counter); | |||||
} | |||||
} | |||||
} |
@@ -1,11 +1,106 @@ | |||||
using System; | |||||
using DotNetty.Buffers; | |||||
using DotNetty.Codecs; | |||||
using DotNetty.Handlers.Timeout; | |||||
using DotNetty.Transport.Bootstrapping; | |||||
using DotNetty.Transport.Channels; | |||||
using DotNetty.Transport.Channels.Sockets; | |||||
using DotNetty.Transport.Libuv; | |||||
using JT808.DotNetty.Client.Handlers; | |||||
using Microsoft.Extensions.Logging; | |||||
using System; | |||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Runtime.InteropServices; | |||||
using System.Text; | using System.Text; | ||||
using Microsoft.Extensions.DependencyInjection; | |||||
using System.Net; | |||||
using System.Threading.Tasks; | |||||
using JT808.DotNetty.Client.Metadata; | |||||
using JT808.DotNetty.Client.Codecs; | |||||
namespace JT808.DotNetty.Client | namespace JT808.DotNetty.Client | ||||
{ | { | ||||
public class JT808TcpClient | |||||
public sealed class JT808TcpClient : IDisposable | |||||
{ | { | ||||
private MultithreadEventLoopGroup group; | |||||
private IChannel clientChannel; | |||||
private bool disposed = false; | |||||
public DeviceConfig DeviceConfig { get; private set; } | |||||
public ILoggerFactory LoggerFactory { get; private set; } | |||||
public JT808TcpClient(DeviceConfig deviceConfig, IServiceProvider serviceProvider) | |||||
{ | |||||
DeviceConfig = deviceConfig; | |||||
LoggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>(); | |||||
group = new MultithreadEventLoopGroup(1); | |||||
Bootstrap bootstrap = new Bootstrap(); | |||||
bootstrap.Group(group); | |||||
bootstrap.Channel<TcpSocketChannel>(); | |||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) | |||||
{ | |||||
bootstrap.Option(ChannelOption.SoReuseport, true); | |||||
} | |||||
bootstrap | |||||
.Option(ChannelOption.SoBacklog, 8192) | |||||
.Handler(new ActionChannelInitializer<IChannel>(channel => | |||||
{ | |||||
channel.Pipeline.AddLast("jt808TcpBuffer", new DelimiterBasedFrameDecoder(int.MaxValue, | |||||
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.BeginFlag }), | |||||
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.EndFlag }))); | |||||
channel.Pipeline.AddLast("systemIdleState", new IdleStateHandler(60, deviceConfig.Heartbeat, 3600)); | |||||
channel.Pipeline.AddLast("jt808TcpDecode", new JT808ClientTcpDecoder()); | |||||
channel.Pipeline.AddLast("jt808TcpEncode", new JT808ClientTcpEncoder(LoggerFactory)); | |||||
channel.Pipeline.AddLast("jt808TcpClientConnection", new JT808TcpClientConnectionHandler(this)); | |||||
channel.Pipeline.AddLast("jt808TcpService", new JT808TcpClientHandler(this)); | |||||
})); | |||||
Task.Run(async () => | |||||
{ | |||||
clientChannel = await bootstrap.ConnectAsync(deviceConfig.TcpHost, deviceConfig.TcpPort); | |||||
}); | |||||
} | |||||
public async void Send(JT808ClientRequest request) | |||||
{ | |||||
if (disposed) return; | |||||
if (clientChannel == null) throw new NullReferenceException("Channel is empty."); | |||||
if (request == null) throw new ArgumentNullException("JT808ClientRequest Parameter is empty."); | |||||
if (clientChannel.Active && clientChannel.Open) | |||||
{ | |||||
await clientChannel.WriteAndFlushAsync(request); | |||||
} | |||||
} | |||||
private void Dispose(bool disposing) | |||||
{ | |||||
if (disposed) | |||||
{ | |||||
return; | |||||
} | |||||
if (disposing) | |||||
{ | |||||
// 清理托管资源 | |||||
group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)); | |||||
} | |||||
disposed = true; | |||||
} | |||||
~JT808TcpClient() | |||||
{ | |||||
//必须为false | |||||
//这表明,隐式清理时,只要处理非托管资源就可以了。 | |||||
Dispose(false); | |||||
} | |||||
public void Dispose() | |||||
{ | |||||
//必须为true | |||||
Dispose(true); | |||||
//通知垃圾回收机制不再调用终结器(析构器) | |||||
GC.SuppressFinalize(this); | |||||
} | |||||
} | } | ||||
} | } |
@@ -0,0 +1,103 @@ | |||||
using JT808.DotNetty.Client.Metadata; | |||||
using JT808.Protocol; | |||||
using JT808.Protocol.MessageBody; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using JT808.Protocol.Enums; | |||||
using JT808.Protocol.Extensions; | |||||
namespace JT808.DotNetty.Client | |||||
{ | |||||
public static class JT808TcpClientExtensions | |||||
{ | |||||
public static void Send(this JT808TcpClient client, JT808Header header, JT808Bodies bodies, int minBufferSize = 1024) | |||||
{ | |||||
JT808Package package = new JT808Package(); | |||||
package.Header = header; | |||||
package.Bodies = bodies; | |||||
package.Header.TerminalPhoneNo = client.DeviceConfig.TerminalPhoneNo; | |||||
package.Header.MsgNum = client.DeviceConfig.MsgSNDistributed.Increment(); | |||||
JT808ClientRequest request = new JT808ClientRequest(package, minBufferSize); | |||||
client.Send(request); | |||||
} | |||||
/// <summary> | |||||
/// 终端通用应答 | |||||
/// </summary> | |||||
/// <param name="client"></param> | |||||
/// <param name="bodies"></param> | |||||
/// <param name="minBufferSize"></param> | |||||
public static void Send(this JT808TcpClient client, JT808_0x0001 bodies, int minBufferSize = 100) | |||||
{ | |||||
JT808Header header = new JT808Header(); | |||||
header.MsgId = JT808MsgId.终端通用应答.ToUInt16Value(); | |||||
client.Send(header, bodies, minBufferSize); | |||||
} | |||||
/// <summary> | |||||
/// 终端心跳 | |||||
/// </summary> | |||||
/// <param name="client"></param> | |||||
/// <param name="bodies"></param> | |||||
/// <param name="minBufferSize"></param> | |||||
public static void Send(this JT808TcpClient client, JT808_0x0002 bodies, int minBufferSize = 100) | |||||
{ | |||||
JT808Header header = new JT808Header(); | |||||
header.MsgId = JT808MsgId.终端心跳.ToUInt16Value(); | |||||
client.Send(header, bodies, minBufferSize); | |||||
} | |||||
/// <summary> | |||||
/// 终端注销 | |||||
/// </summary> | |||||
/// <param name="client"></param> | |||||
/// <param name="bodies"></param> | |||||
/// <param name="minBufferSize"></param> | |||||
public static void Send(this JT808TcpClient client, JT808_0x0003 bodies, int minBufferSize = 100) | |||||
{ | |||||
JT808Header header = new JT808Header(); | |||||
header.MsgId = JT808MsgId.终端注销.ToUInt16Value(); | |||||
client.Send(header, bodies, minBufferSize); | |||||
} | |||||
/// <summary> | |||||
/// 终端鉴权 | |||||
/// </summary> | |||||
/// <param name="client"></param> | |||||
/// <param name="bodies"></param> | |||||
/// <param name="minBufferSize"></param> | |||||
public static void Send(this JT808TcpClient client, JT808_0x0102 bodies, int minBufferSize = 100) | |||||
{ | |||||
JT808Header header = new JT808Header(); | |||||
header.MsgId = JT808MsgId.终端鉴权.ToUInt16Value(); | |||||
client.Send(header, bodies, minBufferSize); | |||||
} | |||||
/// <summary> | |||||
/// 终端注册 | |||||
/// </summary> | |||||
/// <param name="client"></param> | |||||
/// <param name="bodies"></param> | |||||
/// <param name="minBufferSize"></param> | |||||
public static void Send(this JT808TcpClient client, JT808_0x0100 bodies, int minBufferSize = 100) | |||||
{ | |||||
JT808Header header = new JT808Header(); | |||||
header.MsgId = JT808MsgId.终端注册.ToUInt16Value(); | |||||
client.Send(header, bodies, minBufferSize); | |||||
} | |||||
/// <summary> | |||||
/// 位置信息汇报 | |||||
/// </summary> | |||||
/// <param name="client"></param> | |||||
/// <param name="bodies"></param> | |||||
/// <param name="minBufferSize"></param> | |||||
public static void Send(this JT808TcpClient client, JT808_0x0200 bodies, int minBufferSize = 200) | |||||
{ | |||||
JT808Header header = new JT808Header(); | |||||
header.MsgId = JT808MsgId.位置信息汇报.ToUInt16Value(); | |||||
client.Send(header, bodies, minBufferSize); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,53 @@ | |||||
using System; | |||||
using System.Collections.Concurrent; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace JT808.DotNetty.Client | |||||
{ | |||||
public interface IJT808TcpClientFactory : IDisposable | |||||
{ | |||||
JT808TcpClient Create(DeviceConfig deviceConfig); | |||||
} | |||||
public class JT808TcpClientFactory: IJT808TcpClientFactory | |||||
{ | |||||
private readonly ConcurrentDictionary<string, JT808TcpClient> dict; | |||||
private readonly IServiceProvider serviceProvider; | |||||
public JT808TcpClientFactory(IServiceProvider serviceProvider) | |||||
{ | |||||
dict = new ConcurrentDictionary<string, JT808TcpClient>(StringComparer.OrdinalIgnoreCase); | |||||
this.serviceProvider = serviceProvider; | |||||
} | |||||
public JT808TcpClient Create(DeviceConfig deviceConfig) | |||||
{ | |||||
if(dict.TryGetValue(deviceConfig.TerminalPhoneNo,out var client)) | |||||
{ | |||||
return client; | |||||
} | |||||
else | |||||
{ | |||||
JT808TcpClient jT808TcpClient = new JT808TcpClient(deviceConfig, serviceProvider); | |||||
dict.TryAdd(deviceConfig.TerminalPhoneNo, jT808TcpClient); | |||||
return jT808TcpClient; | |||||
} | |||||
} | |||||
public void Dispose() | |||||
{ | |||||
foreach(var client in dict) | |||||
{ | |||||
try | |||||
{ | |||||
client.Value.Dispose(); | |||||
} | |||||
catch | |||||
{ | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,30 @@ | |||||
using JT808.Protocol; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Reflection; | |||||
namespace JT808.DotNetty.Client.Metadata | |||||
{ | |||||
public class JT808ClientRequest | |||||
{ | |||||
public JT808Package Package { get; } | |||||
public byte[] HexData { get; } | |||||
/// <summary> | |||||
/// 根据实际情况适当调整包的大小 | |||||
/// </summary> | |||||
public int MinBufferSize { get;} | |||||
public JT808ClientRequest(JT808Package package,int minBufferSize=1024) | |||||
{ | |||||
Package = package; | |||||
MinBufferSize = minBufferSize; | |||||
} | |||||
public JT808ClientRequest(byte[] hexData) | |||||
{ | |||||
HexData = hexData; | |||||
} | |||||
} | |||||
} |
@@ -8,6 +8,7 @@ namespace JT808.DotNetty.Core.Metadata | |||||
public class JT808Response | public class JT808Response | ||||
{ | { | ||||
public JT808Package Package { get; set; } | public JT808Package Package { get; set; } | ||||
public byte[] HexData { get; set; } | |||||
/// <summary> | /// <summary> | ||||
/// 根据实际情况适当调整包的大小 | /// 根据实际情况适当调整包的大小 | ||||
/// </summary> | /// </summary> | ||||
@@ -23,5 +24,10 @@ namespace JT808.DotNetty.Core.Metadata | |||||
Package = package; | Package = package; | ||||
MinBufferSize = minBufferSize; | MinBufferSize = minBufferSize; | ||||
} | } | ||||
public JT808Response(byte[] hexData) | |||||
{ | |||||
HexData = hexData; | |||||
} | |||||
} | } | ||||
} | } |
@@ -31,7 +31,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.Hosting", "J | |||||
EndProject | EndProject | ||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.WebApiClientTool", "JT808.DotNetty.WebApiClientTool\JT808.DotNetty.WebApiClientTool.csproj", "{9D86C951-94F2-4CBD-B177-8AF31DDB05D8}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.WebApiClientTool", "JT808.DotNetty.WebApiClientTool\JT808.DotNetty.WebApiClientTool.csproj", "{9D86C951-94F2-4CBD-B177-8AF31DDB05D8}" | ||||
EndProject | EndProject | ||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT808.DotNetty.Client", "JT808.DotNetty.Client\JT808.DotNetty.Client.csproj", "{87C08239-C57F-4FC5-9579-05D0723AA4A0}" | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.Client", "JT808.DotNetty.Client\JT808.DotNetty.Client.csproj", "{87C08239-C57F-4FC5-9579-05D0723AA4A0}" | |||||
EndProject | EndProject | ||||
Global | Global | ||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||