Преглед на файлове

1.修改Actions配置

2.移除travis配置
3.增加客户端调用工具
4.增肌基准测试项目
5.修改文档
tags/pipeline-1.0.0
smallchi(Koike) преди 5 години
родител
ревизия
6515166592
променени са 34 файла, в които са добавени 4520 реда и са изтрити 39 реда
  1. +1
    -1
      .github/workflows/dotnetcore.yml
  2. +0
    -21
      .travis.yml
  3. +1
    -1
      README.md
  4. +2
    -6
      src/JT808.DotNetty.Client/JT808TcpClient.cs
  5. +24
    -0
      src/JT808.Gateway.CleintBenchmark/Configs/ClientBenchmarkOptions.cs
  6. +3106
    -0
      src/JT808.Gateway.CleintBenchmark/Configs/NLog.xsd
  7. +36
    -0
      src/JT808.Gateway.CleintBenchmark/Configs/nlog.unix.config
  8. +35
    -0
      src/JT808.Gateway.CleintBenchmark/Configs/nlog.win.config
  9. +63
    -0
      src/JT808.Gateway.CleintBenchmark/Controllers/ReportController.cs
  10. +59
    -0
      src/JT808.Gateway.CleintBenchmark/JT808.Gateway.CleintBenchmark.csproj
  11. +77
    -0
      src/JT808.Gateway.CleintBenchmark/Program.cs
  12. +123
    -0
      src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkHostedService.cs
  13. +13
    -0
      src/JT808.Gateway.CleintBenchmark/wwwroot/echarts.min.js
  14. +153
    -0
      src/JT808.Gateway.CleintBenchmark/wwwroot/index.html
  15. +34
    -0
      src/JT808.Gateway.Client/JT808.Gateway.Client.csproj
  16. +42
    -0
      src/JT808.Gateway.Client/JT808ClientExtensions.cs
  17. +30
    -0
      src/JT808.Gateway.Client/JT808DeviceConfig.cs
  18. +23
    -0
      src/JT808.Gateway.Client/JT808ReportOptions.cs
  19. +269
    -0
      src/JT808.Gateway.Client/JT808TcpClient.cs
  20. +22
    -0
      src/JT808.Gateway.Client/JT808TcpClientExtensions.cs
  21. +71
    -0
      src/JT808.Gateway.Client/JT808TcpClientFactory.cs
  22. +49
    -0
      src/JT808.Gateway.Client/Metadata/JT808AtomicCounter.cs
  23. +30
    -0
      src/JT808.Gateway.Client/Metadata/JT808ClientRequest.cs
  24. +16
    -0
      src/JT808.Gateway.Client/Metadata/JT808Report.cs
  25. +35
    -0
      src/JT808.Gateway.Client/Services/JT808ReceiveAtomicCounterService.cs
  26. +67
    -0
      src/JT808.Gateway.Client/Services/JT808ReportHostedService.cs
  27. +35
    -0
      src/JT808.Gateway.Client/Services/JT808SendAtomicCounterService.cs
  28. +1
    -1
      src/JT808.Gateway.Test/PipeTest.cs
  29. +1
    -0
      src/JT808.Gateway.TestHosting/JT808.Gateway.TestHosting.csproj
  30. +70
    -0
      src/JT808.Gateway.TestHosting/Jobs/UpJob.cs
  31. +5
    -0
      src/JT808.Gateway.TestHosting/Program.cs
  32. +4
    -2
      src/JT808.Gateway.TestHosting/appsettings.json
  33. +22
    -6
      src/JT808.Gateway.sln
  34. +1
    -1
      src/Version.props

+ 1
- 1
.github/workflows/dotnetcore.yml Целия файл

@@ -37,5 +37,5 @@ jobs:
run: dotnet restore ./src/JT808.Gateway.sln
- name: dotnet JT808.Gateway build
run: dotnet build ./src/JT808.Gateway.Test/JT808.Gateway.Test.csproj
- name: dotnet test
- name: dotnet JT808.Gateway test
run: dotnet test ./src/JT808.Gateway.Test/JT808.Gateway.Test.csproj

+ 0
- 21
.travis.yml Целия файл

@@ -1,21 +0,0 @@
language: csharp
solution: JT808.DotNetty.sln
dotnet: 3.1.100
os: linux
mono: none
dist: trusty2
script:
- dotnet restore src/JT808.DotNetty.sln
- dotnet build src/JT808.DotNetty.Tests/JT808.DotNetty.Core.Test/JT808.DotNetty.Core.Test.csproj
- dotnet test src/JT808.DotNetty.Tests/JT808.DotNetty.Core.Test/JT808.DotNetty.Core.Test.csproj
- dotnet build src/JT808.DotNetty.Tests/JT808.DotNetty.Tcp.Test/JT808.DotNetty.Tcp.Test.csproj
- dotnet test src/JT808.DotNetty.Tests/JT808.DotNetty.Tcp.Test/JT808.DotNetty.Tcp.Test.csproj
- dotnet build src/JT808.DotNetty.Tests/JT808.DotNetty.Udp.Test/JT808.DotNetty.Udp.Test.csproj
- dotnet test src/JT808.DotNetty.Tests/JT808.DotNetty.Udp.Test/JT808.DotNetty.Udp.Test.csproj
- dotnet build src/JT808.DotNetty.Tests/JT808.DotNetty.Udp.Test/JT808.DotNetty.Udp.Test.csproj
- dotnet test src/JT808.DotNetty.Tests/JT808.DotNetty.WebApi.Test/JT808.DotNetty.WebApi.Test.csproj
after_success:
- echo successful build!
branches:
only:
- master

+ 1
- 1
README.md Целия файл

@@ -14,7 +14,7 @@

[玩一玩压力测试](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/README.md)

[![MIT Licence](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE)[![Build Status](https://travis-ci.org/SmallChi/JT808DotNetty.svg?branch=master)](https://travis-ci.org/SmallChi/JT808DotNetty)[![Github Build status](https://github.com/SmallChi/JT808Gateway/workflows/.NET%20Core/badge.svg)]()
[![MIT Licence](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE)[![Github Build status](https://github.com/SmallChi/JT808Gateway/workflows/.NET%20Core/badge.svg)]()

## 新网关的优势



+ 2
- 6
src/JT808.DotNetty.Client/JT808TcpClient.cs Целия файл

@@ -41,15 +41,11 @@ namespace JT808.DotNetty.Client
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)
.Option(ChannelOption.Allocator, new PooledByteBufferAllocator())
.Handler(new ActionChannelInitializer<IChannel>(channel =>
{
channel.Pipeline.AddLast("jt808TcpBuffer", new DelimiterBasedFrameDecoder(int.MaxValue,
channel.Pipeline.AddLast("jt808TcpBuffer", new DelimiterBasedFrameDecoder(65535,
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.BeginFlag }),
Unpooled.CopiedBuffer(new byte[] { JT808.Protocol.JT808Package.EndFlag })));
channel.Pipeline.AddLast("systemIdleState", new IdleStateHandler(60, deviceConfig.Heartbeat, 3600));


+ 24
- 0
src/JT808.Gateway.CleintBenchmark/Configs/ClientBenchmarkOptions.cs Целия файл

@@ -0,0 +1,24 @@
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT808.Gateway.CleintBenchmark.Configs
{
public class ClientBenchmarkOptions : IOptions<ClientBenchmarkOptions>
{
public string IP { get; set; }
public int Port { get; set; }
public int DeviceCount { get; set; } = 10;
/// <summary>
/// 5000ms毫秒
/// </summary>
public int Interval { get; set; } = 5000;
/// <summary>
/// 需要多台机器同时访问,那么可以根据这个避开重复终端号
/// 100000-200000-300000
/// </summary>
public int DeviceTemplate { get; set; } = 0;
public ClientBenchmarkOptions Value =>this;
}
}

+ 3106
- 0
src/JT808.Gateway.CleintBenchmark/Configs/NLog.xsd
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 36
- 0
src/JT808.Gateway.CleintBenchmark/Configs/nlog.unix.config Целия файл

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
参考:http://www.cnblogs.com/fuchongjundream/p/3936431.html
autoReload:自动再配置
internalLogFile:可以让NLog把内部的调试和异常信息都写入指定文件里程序没问题了,日志却出了问题。这个该怎么办,到底是哪里不正确了?假如日志本身除了bug该如何解决?这就需要日志排错。把日志的错误信息写入日志。
<nlog throwExceptions="true" />
<nlog internalLogFile="file.txt" />- 设置internalLogFile属性可以让NLog把内部的调试和异常信息都写入指定文件里。
<nlog internalLogLevel="Trace|Debug|Info|Warn|Error|Fatal" /> - 决定内部日志的级别,级别越高,输出的日志信息越简洁。
<nlog internalLogToConsole="false|true" /> - 是否把内部日志输出到标准控制台。
<nlog internalLogToConsoleError="false|true" /> - 是否把内部日志输出到标准错误控制台 (stderr)。
设置throwExceptions属性为“true”可以让NLog不再阻挡这类异常,而是把它们抛给调用者。在部署是这样做可以帮我们快速定位问题。一旦应用程序已经正确配置了,我们建议把throwExceptions的值设为“false”,这样由于日志引发的问题不至于导致应用程序的崩溃。
-->
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogFile="/data/logs/JT808.Gateway.CleintBenchmark/internalLog.txt"
internalLogLevel="Debug" >
<variable name="Directory" value="/data/logs/JT808.Gateway.CleintBenchmark"/>
<targets>
<target name="all" xsi:type="File"
fileName="${Directory}/all/CleintBenchmark.${shortdate}.log"
layout="${date:format=yyyyMMddHHmmss} ${callsite} ${level}:${message} ${onexception:${exception:format=tostring} ${newline} ${stacktrace} ${newline}"/>
<target name="console" xsi:type="ColoredConsole"
useDefaultRowHighlightingRules="false"
layout="${date:format=yyyyMMddHHmmss} ${callsite} ${level} ${message} ${onexception:${exception:format=tostring} ${newline} ${stacktrace} ${newline}">
<highlight-row condition="level == LogLevel.Debug" foregroundColor="DarkGray" />
<highlight-row condition="level == LogLevel.Info" foregroundColor="Gray" />
<highlight-row condition="level == LogLevel.Warn" foregroundColor="Yellow" />
<highlight-row condition="level == LogLevel.Error" foregroundColor="Red" />
<highlight-row condition="level == LogLevel.Fatal" foregroundColor="Red" backgroundColor="White" />
</target>
</targets>
<rules>
<logger name="*" minlevel="Debug" maxlevel="Fatal" writeTo="all,console"/>
</rules>
</nlog>

+ 35
- 0
src/JT808.Gateway.CleintBenchmark/Configs/nlog.win.config Целия файл

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
参考:http://www.cnblogs.com/fuchongjundream/p/3936431.html
autoReload:自动再配置
internalLogFile:可以让NLog把内部的调试和异常信息都写入指定文件里程序没问题了,日志却出了问题。这个该怎么办,到底是哪里不正确了?假如日志本身除了bug该如何解决?这就需要日志排错。把日志的错误信息写入日志。
<nlog throwExceptions="true" />
<nlog internalLogFile="file.txt" />- 设置internalLogFile属性可以让NLog把内部的调试和异常信息都写入指定文件里。
<nlog internalLogLevel="Trace|Debug|Info|Warn|Error|Fatal" /> - 决定内部日志的级别,级别越高,输出的日志信息越简洁。
<nlog internalLogToConsole="false|true" /> - 是否把内部日志输出到标准控制台。
<nlog internalLogToConsoleError="false|true" /> - 是否把内部日志输出到标准错误控制台 (stderr)。
设置throwExceptions属性为“true”可以让NLog不再阻挡这类异常,而是把它们抛给调用者。在部署是这样做可以帮我们快速定位问题。一旦应用程序已经正确配置了,我们建议把throwExceptions的值设为“false”,这样由于日志引发的问题不至于导致应用程序的崩溃。
-->
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogFile="${basedir}/wwwroot/logs/internalLog.txt"
internalLogLevel="Debug" >
<targets>
<target name="all" xsi:type="File"
fileName="${basedir}/wwwroot/logs/all/CleintBenchmark.${shortdate}.log"
layout="${date:format=yyyyMMddHHmmss} ${callsite} ${level}:${message} ${onexception:${exception:format=tostring} ${newline} ${stacktrace} ${newline}"/>
<target name="console" xsi:type="ColoredConsole"
useDefaultRowHighlightingRules="false"
layout="${date:format=yyyyMMddHHmmss} ${callsite} ${level} ${message} ${onexception:${exception:format=tostring} ${newline} ${stacktrace} ${newline}">
<highlight-row condition="level == LogLevel.Debug" foregroundColor="DarkGray" />
<highlight-row condition="level == LogLevel.Info" foregroundColor="Gray" />
<highlight-row condition="level == LogLevel.Warn" foregroundColor="Yellow" />
<highlight-row condition="level == LogLevel.Error" foregroundColor="Red" />
<highlight-row condition="level == LogLevel.Fatal" foregroundColor="Red" backgroundColor="White" />
</target>
</targets>
<rules>
<logger name="*" minlevel="Debug" maxlevel="Fatal" writeTo="all,console"/>
</rules>
</nlog>

+ 63
- 0
src/JT808.Gateway.CleintBenchmark/Controllers/ReportController.cs Целия файл

@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JT808.Gateway.Client;
using JT808.Gateway.Client.Metadata;
using JT808.Gateway.Client.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Primitives;

namespace JT808.Gateway.CleintBenchmark
{
/// <summary>
/// 车辆控制器
/// </summary>
[Route("JT808WebApi")]
[ApiController]
[EnableCors("Domain")]
public class ReportController : ControllerBase
{
private readonly IJT808TcpClientFactory clientFactory;
private readonly JT808ReceiveAtomicCounterService ReceiveAtomicCounterService;
private readonly JT808SendAtomicCounterService SendAtomicCounterService;

/// <summary>
///
/// </summary>
public ReportController(
IJT808TcpClientFactory factory,
JT808ReceiveAtomicCounterService jT808ReceiveAtomicCounterService,
JT808SendAtomicCounterService jT808SendAtomicCounterService)
{
clientFactory = factory;
ReceiveAtomicCounterService = jT808ReceiveAtomicCounterService;
SendAtomicCounterService = jT808SendAtomicCounterService;
}

[HttpPost]
[HttpGet]
[Route("QueryReport")]
public ActionResult<JT808Report> QueryReport()
{
var clients = clientFactory.GetAll();
JT808Report report = new JT808Report()
{
SendTotalCount = SendAtomicCounterService.MsgSuccessCount,
ReceiveTotalCount = ReceiveAtomicCounterService.MsgSuccessCount,
CurrentDate = DateTime.Now,
Connections = clients.Count,
OnlineConnections = clients.Where(w => w.IsOpen).Count(),
OfflineConnections = clients.Where(w => !w.IsOpen).Count(),
};
return report;
}
}
}

+ 59
- 0
src/JT808.Gateway.CleintBenchmark/JT808.Gateway.CleintBenchmark.csproj Целия файл

@@ -0,0 +1,59 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<LangVersion>8.0</LangVersion>
</PropertyGroup>

<ItemGroup>
<Content Remove="wwwroot\echarts.min.js" />
<Content Remove="wwwroot\index.html" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="3.1.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.1" />
<PackageReference Include="NLog.Extensions.Logging" Version="1.6.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\JT808.Gateway.Client\JT808.Gateway.Client.csproj" />
</ItemGroup>

<ItemGroup>
<None Include="wwwroot\echarts.min.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="wwwroot\index.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
<Content Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Configs\nlog.unix.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Configs\nlog.win.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Configs\NLog.xsd">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<SubType>Designer</SubType>
</None>
</ItemGroup>

<ProjectExtensions><VisualStudio><UserProperties appsettings_1json__JsonSchema="" /></VisualStudio></ProjectExtensions>

</Project>

+ 77
- 0
src/JT808.Gateway.CleintBenchmark/Program.cs Целия файл

@@ -0,0 +1,77 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
using System;
using System.Threading.Tasks;
using JT808.Protocol;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Builder;
using JT808.Gateway.Client;
using JT808.Gateway.CleintBenchmark.Configs;
using JT808.Gateway.CleintBenchmark.Services;

namespace JT808.Gateway.CleintBenchmark
{
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);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.Configure(app =>
{
app.UseRouting();
app.UseCors("Domain");
app.UseStaticFiles();
app.UseDefaultFiles("/index.html");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
})
.ConfigureServices((hostContext, services) =>
{
services.AddControllers();
services.AddCors(options =>
options.AddPolicy("Domain", builder =>
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowAnyOrigin()));

});
})
.ConfigureLogging((context, logging) =>
{
if (Environment.OSVersion.Platform == PlatformID.Unix)
{
NLog.LogManager.LoadConfiguration("Configs/nlog.unix.config");
}
else
{
NLog.LogManager.LoadConfiguration("Configs/nlog.win.config");
}
logging.AddNLog();
logging.SetMinimumLevel(LogLevel.Trace);
})
.ConfigureServices((hostContext, services) =>
{
services.Configure<ClientBenchmarkOptions>(hostContext.Configuration.GetSection("ClientBenchmarkOptions"));
services.AddSingleton<ILoggerFactory, LoggerFactory>();
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
services.AddJT808Configure()
.AddJT808Client();
services.AddHostedService<CleintBenchmarkHostedService>();
});
await serverHostBuilder.RunConsoleAsync();
}
}
}

+ 123
- 0
src/JT808.Gateway.CleintBenchmark/Services/CleintBenchmarkHostedService.cs Целия файл

@@ -0,0 +1,123 @@
using JT808.Gateway.CleintBenchmark.Configs;
using JT808.Gateway.Client;
using JT808.Protocol.Enums;
using JT808.Protocol.Extensions;
using JT808.Protocol.MessageBody;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;


namespace JT808.Gateway.CleintBenchmark.Services
{
public class CleintBenchmarkHostedService : IHostedService
{
private readonly ClientBenchmarkOptions clientBenchmarkOptions;

private readonly ILogger logger;

private readonly IJT808TcpClientFactory jT808TcpClientFactory;

private ConcurrentQueue<string> failDeviceNoQueue;

public CleintBenchmarkHostedService(
ILoggerFactory loggerFactory,
IJT808TcpClientFactory jT808TcpClientFactory,
IOptions<ClientBenchmarkOptions> clientBenchmarkOptionsAccessor)
{
this.jT808TcpClientFactory = jT808TcpClientFactory;
clientBenchmarkOptions = clientBenchmarkOptionsAccessor.Value;
logger = loggerFactory.CreateLogger("CleintBenchmarkHostedService");
}
public Task StartAsync(CancellationToken cancellationToken)
{
logger.LogInformation("StartAsync...");
ThreadPool.GetMinThreads(out var minWorkerThreads, out var minCompletionPortThreads);
ThreadPool.GetMaxThreads(out var maxWorkerThreads, out var maxCompletionPortThreads);
logger.LogInformation($"GetMinThreads:{minWorkerThreads}-{minCompletionPortThreads}");
logger.LogInformation($"GetMaxThreads:{maxWorkerThreads}-{maxCompletionPortThreads}");
//先建立连接
failDeviceNoQueue = new ConcurrentQueue<string>();
for (int i=0;i< clientBenchmarkOptions.DeviceCount; i++)
{
string deviceNo = (i + 1 + clientBenchmarkOptions.DeviceTemplate).ToString();
var client = jT808TcpClientFactory.Create(new JT808DeviceConfig(deviceNo,
clientBenchmarkOptions.IP,
clientBenchmarkOptions.Port), cancellationToken);
if (client == null)
{
failDeviceNoQueue.Enqueue(deviceNo);
}
}
int successCount = clientBenchmarkOptions.DeviceCount - failDeviceNoQueue.Count;
logger.LogInformation($"总连接数:{clientBenchmarkOptions.DeviceCount}");
logger.LogInformation($"已建立连接数:{successCount}");
logger.LogInformation($"失败连接数:{failDeviceNoQueue.Count}");
Task.Run(() => {
while (!cancellationToken.IsCancellationRequested)
{
if(failDeviceNoQueue.TryDequeue(out string deviceNo))
{
logger.LogInformation($"尝试重连{deviceNo}...");
var client = jT808TcpClientFactory.Create(new JT808DeviceConfig(deviceNo,
clientBenchmarkOptions.IP,
clientBenchmarkOptions.Port), cancellationToken);
if (client == null)
{
failDeviceNoQueue.Enqueue(deviceNo);
}
Thread.Sleep(1000);
}
else
{
Thread.Sleep(3000);
}
}
}, cancellationToken);
ThreadPool.QueueUserWorkItem((state) =>
{
while (!cancellationToken.IsCancellationRequested)
{
Parallel.ForEach(jT808TcpClientFactory.GetAll(), new ParallelOptions { MaxDegreeOfParallelism = 100 }, (item) =>
{
try
{
int lat = new Random(1000).Next(100000, 180000);
int Lng = new Random(1000).Next(100000, 180000);
item.Send(JT808MsgId.位置信息汇报.Create(item.DeviceConfig.TerminalPhoneNo, new JT808_0x0200()
{
Lat = lat,
Lng = Lng,
GPSTime = DateTime.Now,
Speed = 50,
Direction = 30,
AlarmFlag = 5,
Altitude = 50,
StatusFlag = 10
}));
}
catch (Exception ex)
{
logger.LogError(ex.Message);
}
});
Thread.Sleep(clientBenchmarkOptions.Interval);
}
});
return Task.CompletedTask;
}

public Task StopAsync(CancellationToken cancellationToken)
{
jT808TcpClientFactory.Dispose();
logger.LogInformation("StopAsync...");
return Task.CompletedTask;
}
}
}

+ 13
- 0
src/JT808.Gateway.CleintBenchmark/wwwroot/echarts.min.js
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 153
- 0
src/JT808.Gateway.CleintBenchmark/wwwroot/index.html Целия файл

@@ -0,0 +1,153 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8" />
<title>收发查看</title>
<script src="https://unpkg.com/dayjs"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="/echarts.min.js"></script>
</head>

<body>
<div id="tcpContainer" style="text-align:center;margin:20px auto;width:80%;height: 300px;"></div>
<div id="connContainer" style="text-align:center;margin:20px auto;width:80%;height: 300px;"></div>
<script type="text/javascript">
var tcpDom = document.getElementById("tcpContainer");
var connDom = document.getElementById("connContainer");
var tcpChart = echarts.init(tcpDom);
var connChart = echarts.init(connDom);
var sendData=[];
var receiveData=[];
var onlineData=[];
var offlineData=[];
var timeData=[];
var tcpOption = {
title: {
text: 'TCP收发数'
},
tooltip: {
trigger: 'axis',
axisPointer: {
animation: true
}
},
legend: {
data:['发送总次数','接收总次数']
},
xAxis: {
type: 'category',
boundaryGap: false,
data: timeData
},
yAxis: {
type: 'value',
boundaryGap: [0, '100%'],
splitLine: {
show: true
}
},
series: [{
name: '发送总次数',
type: 'line',
color: "blue",
data: sendData
},{
name: '接收总次数',
type: 'line',
color: "red",
data: receiveData
}]
};
var connOption = {
title: {
text: 'TCP连接数'
},
tooltip: {
trigger: 'axis',
axisPointer: {
animation: true
}
},
legend: {
data:['tcp在线数','tcp离线数']
},
xAxis: {
type: 'category',
boundaryGap: false,
data: timeData
},
yAxis: {
type: 'value',
boundaryGap: [0, '100%'],
splitLine: {
show: true
}
},
series: [{
name: 'tcp在线数',
type: 'line',
color: "blue",
data: onlineData
},{
name: 'tcp离线数',
type: 'line',
color: "red",
data: offlineData
}]
};
setInterval(function () {
axios.post('http://localhost:5000/JT808WebApi/QueryReport')
.then((response) => {
if (response.data) {
if(sendData.length>16){
sendData.shift();
receiveData.shift();
onlineData.shift();
offlineData.shift();
timeData.shift();
}
//console.log(response.data);
timeData.push(dayjs(response.data.currentDate).format('HH:mm:ss'));
sendData.push(response.data.sendTotalCount);
receiveData.push(response.data.receiveTotalCount);
onlineData.push(response.data.onlineConnections);
offlineData.push(response.data.offlineConnections);
tcpChart.setOption({
series: [{
data: sendData
},{
data: receiveData
}],
xAxis:[{
data: timeData
}]
});
connChart.setOption({
series: [{
data: onlineData
},{
data: offlineData
}],
xAxis:[{
data: timeData
}]
});
} else {
alert("没有数据");
}
})
.catch((error) => {
console.log(error);
});
}, 1000);
if (tcpOption && typeof tcpOption === "object") {
tcpChart.setOption(tcpOption, true);
}
if (connOption && typeof connOption === "object") {
connChart.setOption(connOption, true);
}
</script>
</body>

</html>

+ 34
- 0
src/JT808.Gateway.Client/JT808.Gateway.Client.csproj Целия файл

@@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">

<Import Project="..\Version.props" />
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<LangVersion>8.0</LangVersion>
<Copyright>Copyright 2019.</Copyright>
<Authors>SmallChi(Koike)</Authors>
<RepositoryUrl>https://github.com/SmallChi/JT808Gateway</RepositoryUrl>
<PackageProjectUrl>https://github.com/SmallChi/JT808Gateway</PackageProjectUrl>
<licenseUrl>https://github.com/SmallChi/JT808Gateway/blob/master/LICENSE</licenseUrl>
<license>https://github.com/SmallChi/JT808Gateway/blob/master/LICENSE</license>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>$(JT808GatewayPackageVersion)</Version>
<SignAssembly>false</SignAssembly>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageId>JT808.Gateway.Client</PackageId>
<Product>JT808.Gateway.Client</Product>
<Description>基于pipeline实现的JT808客户端工具</Description>
<PackageReleaseNotes>基于pipeline实现的JT808客户端工具</PackageReleaseNotes>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JT808" Version="2.2.6" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="System.IO.Pipelines" Version="4.7.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.1" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.1.1" />
</ItemGroup>

</Project>

+ 42
- 0
src/JT808.Gateway.Client/JT808ClientExtensions.cs Целия файл

@@ -0,0 +1,42 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using JT808.Protocol;
using Microsoft.Extensions.Configuration;
using JT808.Gateway.Client.Services;

namespace JT808.Gateway.Client
{
public static class JT808ClientExtensions
{
public static IJT808Builder AddJT808Client(this IJT808Builder jT808Builder)
{
jT808Builder.Services.AddSingleton<JT808SendAtomicCounterService>();
jT808Builder.Services.AddSingleton<JT808ReceiveAtomicCounterService>();
jT808Builder.Services.AddSingleton<IJT808TcpClientFactory, JT808TcpClientFactory>();
jT808Builder.Services.Configure<JT808ReportOptions>((options)=> { });
jT808Builder.Services.AddHostedService<JT808ReportHostedService>();
return jT808Builder;
}
public static IJT808Builder AddJT808Client(this IJT808Builder jT808Builder, IConfiguration Configuration)
{
jT808Builder.Services.AddSingleton<JT808SendAtomicCounterService>();
jT808Builder.Services.AddSingleton<JT808ReceiveAtomicCounterService>();
jT808Builder.Services.AddSingleton<IJT808TcpClientFactory, JT808TcpClientFactory>();
jT808Builder.Services.Configure<JT808ReportOptions>(Configuration.GetSection("JT808ReportOptions"));
jT808Builder.Services.AddHostedService<JT808ReportHostedService>();
return jT808Builder;
}

public static IJT808Builder AddJT808Client(this IJT808Builder jT808Builder, Action<JT808ReportOptions> reportOptions)
{
jT808Builder.Services.AddSingleton<JT808SendAtomicCounterService>();
jT808Builder.Services.AddSingleton<JT808ReceiveAtomicCounterService>();
jT808Builder.Services.AddSingleton<IJT808TcpClientFactory, JT808TcpClientFactory>();
jT808Builder.Services.Configure(reportOptions);
jT808Builder.Services.AddHostedService<JT808ReportHostedService>();
return jT808Builder;
}
}
}

+ 30
- 0
src/JT808.Gateway.Client/JT808DeviceConfig.cs Целия файл

@@ -0,0 +1,30 @@
using JT808.Protocol;
using JT808.Protocol.Enums;
using JT808.Protocol.Interfaces;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT808.Gateway.Client
{
public class JT808DeviceConfig
{
public JT808DeviceConfig(string terminalPhoneNo, string tcpHost,int tcpPort, JT808Version version= JT808Version.JTT2013)
{
TerminalPhoneNo = terminalPhoneNo;
TcpHost = tcpHost;
TcpPort = tcpPort;
Version = version;
}
public JT808Version Version { get; private set; }
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 IJT808MsgSNDistributed MsgSNDistributed { get; }
}
}

+ 23
- 0
src/JT808.Gateway.Client/JT808ReportOptions.cs Целия файл

@@ -0,0 +1,23 @@
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace JT808.Gateway.Client
{
public class JT808ReportOptions
{
public string FileName { get; set; } = $"JT808Report.{DateTime.Now.ToString("yyyyMMddHHssmm")}.txt";
public string FilePath { get; set; } = AppDomain.CurrentDomain.BaseDirectory;
public string FileFullPath { get { return Path.Combine(FilePath, FileName); } }
public int Interval { get; set; } = 3;
public void FileExistsAndCreate()
{
if(!File.Exists(FileFullPath))
{
File.Create(FileFullPath).Close();
}
}
}
}

+ 269
- 0
src/JT808.Gateway.Client/JT808TcpClient.cs Целия файл

@@ -0,0 +1,269 @@
using System;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO.Pipelines;
using System.Buffers;
using JT808.Protocol;
using Microsoft.Extensions.Logging;
using JT808.Protocol.Exceptions;
using JT808.Protocol.Extensions;
using JT808.Gateway.Client.Services;
using JT808.Gateway.Client.Metadata;
using Microsoft.Extensions.DependencyInjection;

namespace JT808.Gateway.Client
{
public class JT808TcpClient:IDisposable
{
private bool disposed = false;
private Socket clientSocket;
private readonly ILogger Logger;
private readonly JT808Serializer JT808Serializer;
private readonly JT808SendAtomicCounterService SendAtomicCounterService;
private readonly JT808ReceiveAtomicCounterService ReceiveAtomicCounterService;
public JT808DeviceConfig DeviceConfig { get; }
public JT808TcpClient(
JT808DeviceConfig deviceConfig,
IServiceProvider serviceProvider)
{
DeviceConfig = deviceConfig;
SendAtomicCounterService = serviceProvider.GetRequiredService<JT808SendAtomicCounterService>();
ReceiveAtomicCounterService = serviceProvider.GetRequiredService<JT808ReceiveAtomicCounterService>();
JT808Serializer = serviceProvider.GetRequiredService<IJT808Config>().GetSerializer();
Logger = serviceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("JT808TcpClient");
}
public async ValueTask<bool> ConnectAsync(EndPoint remoteEndPoint)
{
clientSocket = new Socket(remoteEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
await clientSocket.ConnectAsync(remoteEndPoint);
return true;
}
catch (Exception e)
{
return false;
}
}
public Task StartAsync(CancellationToken cancellationToken)
{
Task.Run(async () => {
await Task.Factory.StartNew(async (state) =>
{
var session = (Socket)state;
if (Logger.IsEnabled(LogLevel.Information))
{
Logger.LogInformation($"[Connected]:{session.LocalEndPoint} to {session.RemoteEndPoint}");
}
var pipe = new Pipe();
Task writing = FillPipeAsync(session, pipe.Writer);
Task reading = ReadPipeAsync(session, pipe.Reader);
await Task.WhenAll(reading, writing);
}, clientSocket);
}, cancellationToken);
return Task.CompletedTask;
}
private async Task FillPipeAsync(Socket session, PipeWriter writer)
{
while (true)
{
try
{
Memory<byte> memory = writer.GetMemory(10240);
int bytesRead = await session.ReceiveAsync(memory, SocketFlags.None);
if (bytesRead == 0)
{
break;
}
writer.Advance(bytesRead);
}
catch (System.Net.Sockets.SocketException ex)
{
Logger.LogError($"[{ex.SocketErrorCode.ToString()},{ex.Message}]:{session.RemoteEndPoint}");
break;
}
catch (Exception ex)
{
Logger.LogError(ex, $"[Receive Error]:{session.RemoteEndPoint}");
break;
}
FlushResult result = await writer.FlushAsync();
if (result.IsCompleted)
{
break;
}
}
writer.Complete();
}
private async Task ReadPipeAsync(Socket session, PipeReader reader)
{
while (true)
{
ReadResult result = await reader.ReadAsync();
if (result.IsCompleted)
{
break;
}
ReadOnlySequence<byte> buffer = result.Buffer;
SequencePosition consumed = buffer.Start;
SequencePosition examined = buffer.End;
try
{
if (result.IsCanceled) break;
if (buffer.Length > 0)
{
ReaderBuffer(ref buffer, session, out consumed, out examined);
}
}
catch (Exception ex)
{
Close();
break;
}
finally
{
reader.AdvanceTo(consumed, examined);
}
}
reader.Complete();
}
private void ReaderBuffer(ref ReadOnlySequence<byte> buffer, Socket session, out SequencePosition consumed, out SequencePosition examined)
{
consumed = buffer.Start;
examined = buffer.End;
SequenceReader<byte> seqReader = new SequenceReader<byte>(buffer);
if (seqReader.TryPeek(out byte beginMark))
{
if (beginMark != JT808Package.BeginFlag) throw new ArgumentException("Not JT808 Packages.");
}
byte mark = 0;
long totalConsumed = 0;
while (!seqReader.End)
{
if (seqReader.IsNext(JT808Package.BeginFlag, advancePast: true))
{
if (mark == 1)
{
try
{
var package = JT808Serializer.HeaderDeserialize(seqReader.Sequence.Slice(totalConsumed, seqReader.Consumed - totalConsumed).FirstSpan);
ReceiveAtomicCounterService.MsgSuccessIncrement();
if (Logger.IsEnabled(LogLevel.Debug)) Logger.LogDebug($"[Atomic Success Counter]:{ReceiveAtomicCounterService.MsgSuccessCount}");
if (Logger.IsEnabled(LogLevel.Trace)) Logger.LogTrace($"[Accept Hex {session.RemoteEndPoint}]:{package.OriginalData.ToArray().ToHexString()}");
}
catch (JT808Exception ex)
{
Logger.LogError(ex, $"[HeaderDeserialize ErrorCode]:{ ex.ErrorCode}");
}
totalConsumed += (seqReader.Consumed - totalConsumed);
if (seqReader.End) break;
seqReader.Advance(1);
mark = 0;
}
mark++;
}
else
{
seqReader.Advance(1);
}
}
if (seqReader.Length == totalConsumed)
{
examined = consumed = buffer.End;
}
else
{
consumed = buffer.GetPosition(totalConsumed);
}
}
public void Send(JT808ClientRequest message)
{
if (disposed) return;
if (IsOpen)
{
if (message.Package != null)
{
try
{
var sendData = JT808Serializer.SerializeReadOnlySpan(message.Package, minBufferSize: message.MinBufferSize);
clientSocket.Send(sendData);
SendAtomicCounterService.MsgSuccessIncrement();
}
catch (System.Net.Sockets.SocketException ex)
{
Logger.LogError($"[{ex.SocketErrorCode.ToString()},{ex.Message}]");
}
catch (System.Exception ex)
{
Logger.LogError(ex.Message);
}
}
else if (message.HexData != null)
{
clientSocket.Send(message.HexData);
SendAtomicCounterService.MsgSuccessIncrement();
}
}
}

public void Close()
{
if (disposed) return;
var socket = clientSocket;
if (socket == null)
return;
if (Interlocked.CompareExchange(ref clientSocket, null, socket) == socket)
{
try
{
clientSocket.Shutdown(SocketShutdown.Both);
}
finally
{
clientSocket.Close();
}
}
}

private void Dispose(bool disposing)
{
if (disposed) return;
if (disposing)
{
// 清理托管资源
clientSocket.Dispose();
}
disposed = true;
}

~JT808TcpClient()
{
//必须为false
//这表明,隐式清理时,只要处理非托管资源就可以了。
Dispose(false);
}

public void Dispose()
{
//必须为true
Dispose(true);
//通知垃圾回收机制不再调用终结器(析构器)
GC.SuppressFinalize(this);
}

public bool IsOpen
{
get
{
if (disposed) return false;
if (clientSocket != null)
{
return clientSocket.Connected;
}
return false;
}
}
}
}

+ 22
- 0
src/JT808.Gateway.Client/JT808TcpClientExtensions.cs Целия файл

@@ -0,0 +1,22 @@
using JT808.Protocol;
using JT808.Protocol.MessageBody;
using System;
using System.Collections.Generic;
using System.Text;
using JT808.Protocol.Enums;
using JT808.Protocol.Extensions;
using JT808.Gateway.Client.Metadata;

namespace JT808.Gateway.Client
{
public static class JT808TcpClientExtensions
{
public static void Send(this JT808TcpClient client, JT808Package package, int minBufferSize = 4096)
{
package.Header.TerminalPhoneNo = client.DeviceConfig.TerminalPhoneNo;
JT808ClientRequest request = new JT808ClientRequest(package, minBufferSize);
client.Send(request);
}
}

}

+ 71
- 0
src/JT808.Gateway.Client/JT808TcpClientFactory.cs Целия файл

@@ -0,0 +1,71 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;

namespace JT808.Gateway.Client
{
public interface IJT808TcpClientFactory : IDisposable
{
ValueTask<JT808TcpClient> Create(JT808DeviceConfig deviceConfig, CancellationToken cancellationToken);

List<JT808TcpClient> GetAll();
}

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 async ValueTask<JT808TcpClient> Create(JT808DeviceConfig deviceConfig, CancellationToken cancellationToken)
{
if(dict.TryGetValue(deviceConfig.TerminalPhoneNo,out var client))
{
return client;
}
else
{
JT808TcpClient jT808TcpClient = new JT808TcpClient(deviceConfig, serviceProvider);
var successed= await jT808TcpClient.ConnectAsync(new IPEndPoint(IPAddress.Parse(deviceConfig.TcpHost), deviceConfig.TcpPort));
if (successed)
{
await jT808TcpClient.StartAsync(cancellationToken);
dict.TryAdd(deviceConfig.TerminalPhoneNo, jT808TcpClient);
return jT808TcpClient;
}
return default;
}
}

public void Dispose()
{
foreach(var client in dict)
{
try
{
client.Value.Dispose();
}
catch
{
}
}
}

public List<JT808TcpClient> GetAll()
{
return dict.Values.ToList();
}
}
}

+ 49
- 0
src/JT808.Gateway.Client/Metadata/JT808AtomicCounter.cs Целия файл

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace JT808.Gateway.Client.Metadata
{
/// <summary>
///
/// <see cref="Grpc.Core.Internal"/>
/// </summary>
internal class JT808AtomicCounter
{
long counter = 0;

public JT808AtomicCounter(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);
}
}
}
}

+ 30
- 0
src/JT808.Gateway.Client/Metadata/JT808ClientRequest.cs Целия файл

@@ -0,0 +1,30 @@
using JT808.Protocol;
using System;
using System.Collections.Generic;
using System.Reflection;

namespace JT808.Gateway.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;
}
}
}

+ 16
- 0
src/JT808.Gateway.Client/Metadata/JT808Report.cs Целия файл

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace JT808.Gateway.Client.Metadata
{
public class JT808Report
{
public long SendTotalCount { get; set; }
public long ReceiveTotalCount { get; set; }
public DateTime CurrentDate { get; set; }
public int Connections { get; set; }
public int OnlineConnections { get; set; }
public int OfflineConnections { get; set; }
}
}

+ 35
- 0
src/JT808.Gateway.Client/Services/JT808ReceiveAtomicCounterService.cs Целия файл

@@ -0,0 +1,35 @@
using JT808.Gateway.Client.Metadata;

namespace JT808.Gateway.Client.Services
{
/// <summary>
/// 接收计数包服务
/// </summary>
public class JT808ReceiveAtomicCounterService
{
private readonly JT808AtomicCounter MsgSuccessCounter;

public JT808ReceiveAtomicCounterService()
{
MsgSuccessCounter=new JT808AtomicCounter();
}

public void Reset()
{
MsgSuccessCounter.Reset();
}

public long MsgSuccessIncrement()
{
return MsgSuccessCounter.Increment();
}

public long MsgSuccessCount
{
get
{
return MsgSuccessCounter.Count;
}
}
}
}

+ 67
- 0
src/JT808.Gateway.Client/Services/JT808ReportHostedService.cs Целия файл

@@ -0,0 +1,67 @@
using JT808.Gateway.Client.Metadata;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace JT808.Gateway.Client.Services
{
public class JT808ReportHostedService : BackgroundService
{
private readonly IOptionsMonitor<JT808ReportOptions> jT808ReportOptions;
private readonly JT808ReceiveAtomicCounterService jT808ReceiveAtomicCounterService;
private readonly JT808SendAtomicCounterService jT808SendAtomicCounterService;
private readonly IJT808TcpClientFactory jT808TcpClientFactory;
private readonly ILogger logger;

public JT808ReportHostedService(
ILoggerFactory loggerFactory,
IOptionsMonitor<JT808ReportOptions> jT808ReportOptionsAccessor,
JT808ReceiveAtomicCounterService jT808ReceiveAtomicCounterService,
JT808SendAtomicCounterService jT808SendAtomicCounterService,
IJT808TcpClientFactory jT808TcpClientFactory)
{
logger = loggerFactory.CreateLogger("JT808ReportHostedService");
jT808ReportOptions = jT808ReportOptionsAccessor;
jT808ReportOptions.CurrentValue.FileExistsAndCreate();
this.jT808ReceiveAtomicCounterService = jT808ReceiveAtomicCounterService;
this.jT808SendAtomicCounterService = jT808SendAtomicCounterService;
this.jT808TcpClientFactory = jT808TcpClientFactory;
jT808ReportOptions.OnChange((options) => { options.FileExistsAndCreate(); });
}

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var clients = jT808TcpClientFactory.GetAll();
JT808Report report = new JT808Report()
{
SendTotalCount = jT808SendAtomicCounterService.MsgSuccessCount,
ReceiveTotalCount = jT808ReceiveAtomicCounterService.MsgSuccessCount,
CurrentDate = DateTime.Now,
Connections = clients.Count,
OnlineConnections = clients.Where(w => w.IsOpen).Count(),
OfflineConnections = clients.Where(w => !w.IsOpen).Count(),
};
string json = JsonConvert.SerializeObject(report);
if (logger.IsEnabled(LogLevel.Debug))
{
logger.LogDebug(json);
}
using (var sw=new StreamWriter(jT808ReportOptions.CurrentValue.FileFullPath,true))
{
sw.WriteLine(json);
}
await Task.Delay(TimeSpan.FromSeconds(jT808ReportOptions.CurrentValue.Interval), stoppingToken);
}
}
}
}

+ 35
- 0
src/JT808.Gateway.Client/Services/JT808SendAtomicCounterService.cs Целия файл

@@ -0,0 +1,35 @@
using JT808.Gateway.Client.Metadata;

namespace JT808.Gateway.Client.Services
{
/// <summary>
/// 发送计数包服务
/// </summary>
public class JT808SendAtomicCounterService
{
private readonly JT808AtomicCounter MsgSuccessCounter;

public JT808SendAtomicCounterService()
{
MsgSuccessCounter=new JT808AtomicCounter();
}

public void Reset()
{
MsgSuccessCounter.Reset();
}

public long MsgSuccessIncrement()
{
return MsgSuccessCounter.Increment();
}

public long MsgSuccessCount
{
get
{
return MsgSuccessCounter.Count;
}
}
}
}

+ 1
- 1
src/JT808.Gateway.Test/PipeTest.cs Целия файл

@@ -86,7 +86,7 @@ namespace JT808.Gateway.Test
[Fact]
public void Test3()
{
Assert.Throws<Exception>(() =>
Assert.Throws<ArgumentException>(() =>
{
var reader = new ReadOnlySequence<byte>(new byte[] { 0, 1, 2, 0x7E });
SequenceReader<byte> seqReader = new SequenceReader<byte>(reader);


+ 1
- 0
src/JT808.Gateway.TestHosting/JT808.Gateway.TestHosting.csproj Целия файл

@@ -14,6 +14,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\JT808.Gateway.Client\JT808.Gateway.Client.csproj" />
<ProjectReference Include="..\JT808.Gateway.InMemoryMQ\JT808.Gateway.InMemoryMQ.csproj" />
<ProjectReference Include="..\JT808.Gateway.Kafka\JT808.Gateway.Kafka.csproj" />
<ProjectReference Include="..\JT808.Gateway.Services\JT808.Gateway.ReplyMessage\JT808.Gateway.ReplyMessage.csproj" />


+ 70
- 0
src/JT808.Gateway.TestHosting/Jobs/UpJob.cs Целия файл

@@ -0,0 +1,70 @@
using JT808.Gateway.Client;
using JT808.Protocol.Enums;
using JT808.Protocol.Extensions;
using JT808.Protocol.MessageBody;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace JT808.Gateway.TestHosting.Jobs
{
public class UpJob : IHostedService
{
private readonly IJT808TcpClientFactory jT808TcpClientFactory;
private readonly ILogger Logger;
public UpJob(
ILoggerFactory loggerFactory,
IJT808TcpClientFactory jT808TcpClientFactory)
{
Logger = loggerFactory.CreateLogger("UpJob");
this.jT808TcpClientFactory = jT808TcpClientFactory;
}

public Task StartAsync(CancellationToken cancellationToken)
{
Task.Run(async () =>
{
await Task.Delay(2 * 1000);
var client = await jT808TcpClientFactory.Create(new JT808DeviceConfig("1234567890", "127.0.0.1", 808), cancellationToken);
if (client != null)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
int lat = new Random(1000).Next(100000, 180000);
int Lng = new Random(1000).Next(100000, 180000);
client.Send(JT808MsgId.位置信息汇报.Create(client.DeviceConfig.TerminalPhoneNo, new JT808_0x0200()
{
Lat = lat,
Lng = Lng,
GPSTime = DateTime.Now,
Speed = 50,
Direction = 30,
AlarmFlag = 5,
Altitude = 50,
StatusFlag = 10
}));
}
catch (Exception ex)
{
Logger.LogError(ex.Message);
}
await Task.Delay(3 * 1000);
}
}
}, cancellationToken);
return Task.CompletedTask;
}

public Task StopAsync(CancellationToken cancellationToken)
{
jT808TcpClientFactory.Dispose();
return Task.CompletedTask;
}
}
}

+ 5
- 0
src/JT808.Gateway.TestHosting/Program.cs Целия файл

@@ -10,6 +10,7 @@ using JT808.Gateway.TestHosting.Jobs;
using JT808.Gateway.Kafka;
using JT808.Gateway.InMemoryMQ;
using JT808.Gateway.ReplyMessage;
using JT808.Gateway.Client;

namespace JT808.Gateway.TestHosting
{
@@ -36,6 +37,7 @@ namespace JT808.Gateway.TestHosting
services.AddSingleton<ILoggerFactory, LoggerFactory>();
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
services.AddJT808Configure()
//.AddJT808Client()
//.AddJT808Gateway(options =>
//{
// options.TcpPort = 808;
@@ -53,7 +55,10 @@ namespace JT808.Gateway.TestHosting
//.AddJT808ServerKafkaMsgReplyConsumer(hostContext.Configuration)
//.AddJT808ServerKafkaSessionProducer(hostContext.Configuration)
;
//grpc客户端调用
//services.AddHostedService<CallGrpcClientJob>();
//客户端测试
//services.AddHostedService<UpJob>();
});

await serverHostBuilder.RunConsoleAsync();


+ 4
- 2
src/JT808.Gateway.TestHosting/appsettings.json Целия файл

@@ -1,6 +1,8 @@
{
{
"JT808Configuration": {
"TcpPort": 808,
"UdpPort": 808
"UdpPort": 808,
"MiniNumBufferSize": 51200,
"SoBacklog": 65535
}
}

+ 22
- 6
src/JT808.Gateway.sln Целия файл

@@ -7,8 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway", "JT808.Gate
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.TestHosting", "JT808.Gateway.TestHosting\JT808.Gateway.TestHosting.csproj", "{AE40AFE0-0950-442C-A74C-10CDF53E9F36}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.Test", "JT808.Gateway.Test\JT808.Gateway.Test.csproj", "{28C9BC4D-7B28-4E65-971A-7156E5EE0ADF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.Abstractions", "JT808.Gateway.Abstractions\JT808.Gateway.Abstractions.csproj", "{3AA17DF7-A1B3-449C-93C2-45B051C32933}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.Kafka", "JT808.Gateway.Kafka\JT808.Gateway.Kafka.csproj", "{274C048E-A8E3-4422-A578-A10A97DF36F2}"
@@ -29,6 +27,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.Traffic", "JT
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.InMemoryMQ", "JT808.Gateway.InMemoryMQ\JT808.Gateway.InMemoryMQ.csproj", "{F7460E8F-B23E-4407-8802-375DE37BED00}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.Client", "JT808.Gateway.Client\JT808.Gateway.Client.csproj", "{AC3070AC-A938-4213-A562-C079BB4A3F9E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{7CBAACEE-19BF-499A-8C41-36A1324D45E9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.Test", "JT808.Gateway.Test\JT808.Gateway.Test.csproj", "{1E230D1B-BDFC-4D0A-9B34-592280A723BD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Gateway.CleintBenchmark", "JT808.Gateway.CleintBenchmark\JT808.Gateway.CleintBenchmark.csproj", "{0FBC9E4F-8585-4820-ACF1-145A14B3A727}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -43,10 +49,6 @@ Global
{AE40AFE0-0950-442C-A74C-10CDF53E9F36}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE40AFE0-0950-442C-A74C-10CDF53E9F36}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AE40AFE0-0950-442C-A74C-10CDF53E9F36}.Release|Any CPU.Build.0 = Release|Any CPU
{28C9BC4D-7B28-4E65-971A-7156E5EE0ADF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{28C9BC4D-7B28-4E65-971A-7156E5EE0ADF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{28C9BC4D-7B28-4E65-971A-7156E5EE0ADF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{28C9BC4D-7B28-4E65-971A-7156E5EE0ADF}.Release|Any CPU.Build.0 = Release|Any CPU
{3AA17DF7-A1B3-449C-93C2-45B051C32933}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3AA17DF7-A1B3-449C-93C2-45B051C32933}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3AA17DF7-A1B3-449C-93C2-45B051C32933}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -83,17 +85,31 @@ Global
{F7460E8F-B23E-4407-8802-375DE37BED00}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F7460E8F-B23E-4407-8802-375DE37BED00}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F7460E8F-B23E-4407-8802-375DE37BED00}.Release|Any CPU.Build.0 = Release|Any CPU
{AC3070AC-A938-4213-A562-C079BB4A3F9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AC3070AC-A938-4213-A562-C079BB4A3F9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AC3070AC-A938-4213-A562-C079BB4A3F9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AC3070AC-A938-4213-A562-C079BB4A3F9E}.Release|Any CPU.Build.0 = Release|Any CPU
{1E230D1B-BDFC-4D0A-9B34-592280A723BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E230D1B-BDFC-4D0A-9B34-592280A723BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E230D1B-BDFC-4D0A-9B34-592280A723BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E230D1B-BDFC-4D0A-9B34-592280A723BD}.Release|Any CPU.Build.0 = Release|Any CPU
{0FBC9E4F-8585-4820-ACF1-145A14B3A727}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0FBC9E4F-8585-4820-ACF1-145A14B3A727}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0FBC9E4F-8585-4820-ACF1-145A14B3A727}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0FBC9E4F-8585-4820-ACF1-145A14B3A727}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{AE40AFE0-0950-442C-A74C-10CDF53E9F36} = {7CBAACEE-19BF-499A-8C41-36A1324D45E9}
{D62E3054-6924-4F1A-9BEF-E52B191F16B6} = {3EF8490D-C993-49D8-8A3D-493B7F259D70}
{A242A839-4F00-4434-A7E8-7E3BEBA5B75C} = {3EF8490D-C993-49D8-8A3D-493B7F259D70}
{1CB84599-5F56-4461-A451-DF16E3854AB9} = {3EF8490D-C993-49D8-8A3D-493B7F259D70}
{604BB5CF-9ED1-4D78-9328-59436E2B4EB4} = {3EF8490D-C993-49D8-8A3D-493B7F259D70}
{598E445A-AF2E-42F0-98F4-18EC22E473FC} = {3EF8490D-C993-49D8-8A3D-493B7F259D70}
{8FCC6D65-8A49-4AE7-8B19-F255100849D6} = {3EF8490D-C993-49D8-8A3D-493B7F259D70}
{1E230D1B-BDFC-4D0A-9B34-592280A723BD} = {7CBAACEE-19BF-499A-8C41-36A1324D45E9}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AA9303A7-6FB3-4572-88AA-3302E85330D1}


+ 1
- 1
src/Version.props Целия файл

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<JT808DotNettyPackageVersion>2.3.1</JT808DotNettyPackageVersion>
<JT808GatewayPackageVersion>1.0.0-preview3</JT808GatewayPackageVersion>
<JT808GatewayPackageVersion>1.0.0-preview4</JT808GatewayPackageVersion>
</PropertyGroup>
</Project>

Зареждане…
Отказ
Запис