浏览代码

v2.1.2

tags/v2.1.2
smallchi 5 年前
当前提交
59e216ebfd
共有 100 个文件被更改,包括 7464 次插入0 次删除
  1. +333
    -0
      .gitignore
  2. +21
    -0
      LICENSE
  3. +133
    -0
      README.md
  4. +512
    -0
      api/README.md
  5. +16
    -0
      doc/README.md
  6. 二进制
      doc/img/demo1.png
  7. 二进制
      doc/img/demo2.png
  8. 二进制
      doc/img/design_model.png
  9. 二进制
      doc/img/performance_1000.png
  10. 二进制
      doc/img/performance_10000.png
  11. 二进制
      doc/img/performance_2000.png
  12. 二进制
      doc/img/performance_5000.png
  13. +19
    -0
      simples/JT808.DotNetty.SimpleClient/JT808.DotNetty.SimpleClient.csproj
  14. +38
    -0
      simples/JT808.DotNetty.SimpleClient/Program.cs
  15. +68
    -0
      simples/JT808.DotNetty.SimpleClient/Services/UpService.cs
  16. +59
    -0
      simples/JT808.DotNetty.SimpleServer/Handlers/JT808MsgIdTcpSimpleHandler.cs
  17. +25
    -0
      simples/JT808.DotNetty.SimpleServer/JT808.DotNetty.SimpleServer.csproj
  18. +47
    -0
      simples/JT808.DotNetty.SimpleServer/Program.cs
  19. +125
    -0
      simples/JT808.DotNetty.Simples.sln
  20. +12
    -0
      src/JT808.DotNetty.Abstractions/Dtos/JT808AtomicCounterDto.cs
  21. +15
    -0
      src/JT808.DotNetty.Abstractions/Dtos/JT808DefaultResultDto.cs
  22. +37
    -0
      src/JT808.DotNetty.Abstractions/Dtos/JT808IPAddressDto.cs
  23. +29
    -0
      src/JT808.DotNetty.Abstractions/Dtos/JT808ResultDto.cs
  24. +33
    -0
      src/JT808.DotNetty.Abstractions/Dtos/JT808SystemCollectInfoDto.cs
  25. +24
    -0
      src/JT808.DotNetty.Abstractions/Dtos/JT808TcpSessionInfoDto.cs
  26. +20
    -0
      src/JT808.DotNetty.Abstractions/Dtos/JT808TrafficInfoDto.cs
  27. +24
    -0
      src/JT808.DotNetty.Abstractions/Dtos/JT808UdpSessionInfoDto.cs
  28. +11
    -0
      src/JT808.DotNetty.Abstractions/Dtos/JT808UnificationSendRequestDto.cs
  29. +15
    -0
      src/JT808.DotNetty.Abstractions/Enums/JT808TransportProtocolType.cs
  30. +22
    -0
      src/JT808.DotNetty.Abstractions/IJT808DownlinkPacket.cs
  31. +12
    -0
      src/JT808.DotNetty.Abstractions/IJT808SessionPublishing.cs
  32. +15
    -0
      src/JT808.DotNetty.Abstractions/IJT808SourcePackageDispatcher.cs
  33. +19
    -0
      src/JT808.DotNetty.Abstractions/IJT808UplinkPacket.cs
  34. +10
    -0
      src/JT808.DotNetty.Abstractions/JT808.DotNetty.Abstractions.csproj
  35. +84
    -0
      src/JT808.DotNetty.Abstractions/JT808Constants.cs
  36. +13
    -0
      src/JT808.DotNetty.Abstractions/Properties/PublishProfiles/FolderProfile.pubxml
  37. +6
    -0
      src/JT808.DotNetty.Abstractions/Properties/PublishProfiles/FolderProfile.pubxml.user
  38. +19
    -0
      src/JT808.DotNetty.CleintBenchmark/Configs/ClientBenchmarkOptions.cs
  39. +3106
    -0
      src/JT808.DotNetty.CleintBenchmark/Configs/NLog.xsd
  40. +36
    -0
      src/JT808.DotNetty.CleintBenchmark/Configs/nlog.unix.config
  41. +35
    -0
      src/JT808.DotNetty.CleintBenchmark/Configs/nlog.win.config
  42. +37
    -0
      src/JT808.DotNetty.CleintBenchmark/JT808.DotNetty.CleintBenchmark.csproj
  43. +49
    -0
      src/JT808.DotNetty.CleintBenchmark/Program.cs
  44. +83
    -0
      src/JT808.DotNetty.CleintBenchmark/Services/CleintBenchmarkHostedService.cs
  45. +55
    -0
      src/JT808.DotNetty.CleintBenchmark/Services/CleintBenchmarkReportHostedService.cs
  46. +20
    -0
      src/JT808.DotNetty.CleintBenchmark/appsettings.json
  47. +20
    -0
      src/JT808.DotNetty.Client/Codecs/JT808ClientTcpDecoder.cs
  48. +54
    -0
      src/JT808.DotNetty.Client/Codecs/JT808ClientTcpEncoder.cs
  49. +28
    -0
      src/JT808.DotNetty.Client/DeviceConfig.cs
  50. +95
    -0
      src/JT808.DotNetty.Client/Handlers/JT808TcpClientConnectionHandler.cs
  51. +30
    -0
      src/JT808.DotNetty.Client/Handlers/JT808TcpClientHandler.cs
  52. +31
    -0
      src/JT808.DotNetty.Client/JT808.DotNetty.Client.csproj
  53. +21
    -0
      src/JT808.DotNetty.Client/JT808ClientDotnettyExtensions.cs
  54. +16
    -0
      src/JT808.DotNetty.Client/JT808ClientMsgSNDistributedImpl.cs
  55. +116
    -0
      src/JT808.DotNetty.Client/JT808TcpClient.cs
  56. +103
    -0
      src/JT808.DotNetty.Client/JT808TcpClientExtensions.cs
  57. +62
    -0
      src/JT808.DotNetty.Client/JT808TcpClientFactory.cs
  58. +49
    -0
      src/JT808.DotNetty.Client/Metadata/JT808AtomicCounter.cs
  59. +30
    -0
      src/JT808.DotNetty.Client/Metadata/JT808ClientRequest.cs
  60. +16
    -0
      src/JT808.DotNetty.Client/Metadata/JT808Report.cs
  61. +35
    -0
      src/JT808.DotNetty.Client/Services/JT808ReceiveAtomicCounterService.cs
  62. +37
    -0
      src/JT808.DotNetty.Client/Services/JT808ReportHostedService.cs
  63. +42
    -0
      src/JT808.DotNetty.Client/Services/JT808ReportService.cs
  64. +35
    -0
      src/JT808.DotNetty.Client/Services/JT808SendAtomicCounterService.cs
  65. +20
    -0
      src/JT808.DotNetty.Core/Codecs/JT808TcpDecoder.cs
  66. +67
    -0
      src/JT808.DotNetty.Core/Codecs/JT808TcpEncoder.cs
  67. +21
    -0
      src/JT808.DotNetty.Core/Codecs/JT808UdpDecoder.cs
  68. +31
    -0
      src/JT808.DotNetty.Core/Configurations/JT808ClientConfiguration.cs
  69. +47
    -0
      src/JT808.DotNetty.Core/Configurations/JT808Configuration.cs
  70. +29
    -0
      src/JT808.DotNetty.Core/Converters/JsonByteArrayHexConverter.cs
  71. +26
    -0
      src/JT808.DotNetty.Core/Converters/JsonIPAddressConverter.cs
  72. +32
    -0
      src/JT808.DotNetty.Core/Converters/JsonIPEndPointConverter.cs
  73. +91
    -0
      src/JT808.DotNetty.Core/Handlers/JT808MsgIdHttpHandlerBase.cs
  74. +153
    -0
      src/JT808.DotNetty.Core/Handlers/JT808MsgIdTcpHandlerBase.cs
  75. +154
    -0
      src/JT808.DotNetty.Core/Handlers/JT808MsgIdUdpHandlerBase.cs
  76. +33
    -0
      src/JT808.DotNetty.Core/Impls/JT808DatagramPacketImpl.cs
  77. +17
    -0
      src/JT808.DotNetty.Core/Impls/JT808DownlinkPacketEmptyImpl.cs
  78. +56
    -0
      src/JT808.DotNetty.Core/Impls/JT808NettyBuilderDefault.cs
  79. +13
    -0
      src/JT808.DotNetty.Core/Impls/JT808SessionPublishingEmptyImpl.cs
  80. +16
    -0
      src/JT808.DotNetty.Core/Impls/JT808SourcePackageDispatcherEmptyImpl.cs
  81. +17
    -0
      src/JT808.DotNetty.Core/Impls/JT808UplinkPacketEmptyImpl.cs
  82. +13
    -0
      src/JT808.DotNetty.Core/Interfaces/IJT808DatagramPacket.cs
  83. +19
    -0
      src/JT808.DotNetty.Core/Interfaces/IJT808NettyBuilder.cs
  84. +17
    -0
      src/JT808.DotNetty.Core/Interfaces/IJT808Reply.cs
  85. +20
    -0
      src/JT808.DotNetty.Core/Interfaces/IJT808TcpCustomMsgIdHandler.cs
  86. +17
    -0
      src/JT808.DotNetty.Core/Interfaces/IJT808TcpNettyBuilder.cs
  87. +25
    -0
      src/JT808.DotNetty.Core/Interfaces/IJT808TcpSessionService.cs
  88. +20
    -0
      src/JT808.DotNetty.Core/Interfaces/IJT808UdpCustomMsgIdHandler.cs
  89. +17
    -0
      src/JT808.DotNetty.Core/Interfaces/IJT808UdpNettyBuilder.cs
  90. +25
    -0
      src/JT808.DotNetty.Core/Interfaces/IJT808UdpSessionService.cs
  91. +12
    -0
      src/JT808.DotNetty.Core/Interfaces/IJT808UnificationTcpSendService.cs
  92. +12
    -0
      src/JT808.DotNetty.Core/Interfaces/IJT808UnificationUdpSendService.cs
  93. +14
    -0
      src/JT808.DotNetty.Core/Interfaces/IJT808WebApiNettyBuilder.cs
  94. +29
    -0
      src/JT808.DotNetty.Core/JT808.DotNetty.Core.csproj
  95. +74
    -0
      src/JT808.DotNetty.Core/JT808BackgroundService.cs
  96. +96
    -0
      src/JT808.DotNetty.Core/JT808CoreDotnettyExtensions.cs
  97. +50
    -0
      src/JT808.DotNetty.Core/JT808SimpleTcpClient.cs
  98. +48
    -0
      src/JT808.DotNetty.Core/JT808SimpleUdpClient.cs
  99. +38
    -0
      src/JT808.DotNetty.Core/Jobs/JT808TcpAtomicCouterResetDailyJob.cs
  100. +38
    -0
      src/JT808.DotNetty.Core/Jobs/JT808TcpTrafficResetDailyJob.cs

+ 333
- 0
.gitignore 查看文件

@@ -0,0 +1,333 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/

# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# Visual Studio 2017 auto generated files
Generated\ Files/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUNIT
*.VisualState.xml
TestResult.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# Benchmark Results
BenchmarkDotNet.Artifacts/

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json

# StyleCop
StyleCopReport.xml

# Files built by Visual Studio
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# Visual Studio Trace Files
*.e2e

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# JustCode is a .NET coding add-in
.JustCode

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json

# Visual Studio code coverage results
*.coverage
*.coveragexml

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs

# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak

# SQL Server files
*.mdf
*.ldf
*.ndf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/

# FAKE - F# Make
.fake/

# JetBrains Rider
.idea/
*.sln.iml

# CodeRush
.cr/

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config

# Tabs Studio
*.tss

# Telerik's JustMock configuration file
*.jmconfig

# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

# OpenCover UI analysis results
OpenCover/

# Azure Stream Analytics local run output
ASALocalRun/

# MSBuild Binary and Structured Log
*.binlog

# NVidia Nsight GPU debugger configuration file
*.nvuser

# MFractors (Xamarin productivity tool) working folder
.mfractor/
*.json
/nupkgs
/src/JT808.DotNetty.Admin/tools/protoc-gen-grpc-web-1.0.3-windows-x86_64.exe

+ 21
- 0
LICENSE 查看文件

@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2018 SmallChi(Koike)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

+ 133
- 0
README.md 查看文件

@@ -0,0 +1,133 @@
# JT808DotNetty

基于DotNetty封装的JT808DotNetty支持TCP/UDP通用消息业务处理

[了解JT808协议进这边](https://github.com/SmallChi/JT808)

[了解JT809协议进这边](https://github.com/SmallChi/JT809)

[了解JT1078协议进这边](https://github.com/SmallChi/JT1078)

[了解JTNE协议进这边](https://github.com/SmallChi/JTNewEnergy)

[玩一玩压力测试](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)

## 新网关的优势:

1. 跨平台
2. 借助 .NET Core模块化的思想
3. 单机同时一万辆车在线不是梦(真有一万辆车那都很吃香了<( ̄3 ̄)> <( ̄3 ̄)> <( ̄3 ̄)> )
4. 简单易上手

## 设计模型

![design_model](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/design_model.png)

## 基于Tcp的消息业务处理程序(JT808.DotNetty.Tcp)

通过继承JT808.DotNetty.Core.Handlers.JT808MsgIdTcpHandlerBase去实现自定义的消息业务处理程序。

## 基于Udp的消息业务处理程序(JT808.DotNetty.Udp)

通过继承JT808.DotNetty.Core.Handlers.JT808MsgIdUdpHandlerBase去实现自定义的消息业务处理程序。

## 基于WebApi的消息业务处理程序(JT808.DotNetty.WebApi)

通过继承JT808.DotNetty.Core.Handlers.JT808MsgIdHttpHandlerBase去实现自定义的WebApi接口服务。

[WebApi公共接口服务](https://github.com/SmallChi/JT808DotNetty/blob/master/api/README.md)

## 集成接口功能(JT808.DotNetty.Abstractions)

|接口名称|接口说明|使用场景|
|:------:|:------|:------|
| IJT808SessionPublishing| 会话通知(在线/离线)| 有些超长待机的设备,不会实时保持连接,那么通过平台下发的命令是无法到达的,这时候就需要设备一上线,就即时通知服务去处理,然后在即时的下发消息到设备。|
| IJT808SourcePackageDispatcher| 原包分发器| 需要将源数据转给其他平台|
| IJT808UplinkPacket| 上行数据包处理接口| 平台需要查看网关的上行数据日志(可以配合InfluxDB使用)|
| IJT808DownlinkPacket| 下行数据包处理接口| 平台需要查看网关的下行数据日志(可以配合InfluxDB使用)|

> 只要实现IJT808SessionPublishing接口的任意一款MQ都能实现该功能。

> 使用物联网卡通过udp下发指令时,存储的那个socket地址端口,有效期非常短,不速度快点下发,那个socket地址端口就可能映射到别的对应卡去了,所以此处采用跟随设备消息下发指令。

## NuGet安装

| Package Name | Version | Downloads |
| --------------------- | -------------------------------------------------- | --------------------------------------------------- |
| Install-Package JT808.DotNetty.Core | ![JT808](https://img.shields.io/nuget/v/JT808.DotNetty.Core.svg) | ![JT808](https://img.shields.io/nuget/dt/JT808.DotNetty.Core.svg) |
| Install-Package JT808.DotNetty.Abstractions | ![JT808](https://img.shields.io/nuget/v/JT808.DotNetty.Abstractions.svg) | ![JT808](https://img.shields.io/nuget/dt/JT808.DotNetty.Abstractions.svg) |
| Install-Package JT808.DotNetty.Tcp | ![JT808](https://img.shields.io/nuget/v/JT808.DotNetty.Tcp.svg) | ![JT808](https://img.shields.io/nuget/dt/JT808.DotNetty.Tcp.svg) |
| Install-Package JT808.DotNetty.Udp | ![JT808](https://img.shields.io/nuget/v/JT808.DotNetty.Udp.svg) | ![JT808](https://img.shields.io/nuget/dt/JT808.DotNetty.Udp.svg) |
| Install-Package JT808.DotNetty.WebApi | ![JT808](https://img.shields.io/nuget/v/JT808.DotNetty.WebApi.svg) | ![JT808](https://img.shields.io/nuget/dt/JT808.DotNetty.WebApi.svg) |
| Install-Package JT808.DotNetty.WebApiClientTool | ![JT808](https://img.shields.io/nuget/v/JT808.DotNetty.WebApiClientTool.svg) | ![JT808](https://img.shields.io/nuget/dt/JT808.DotNetty.WebApiClientTool.svg) |

## 举个栗子1

``` demo1
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.AddJT808Configure()
.AddJT808NettyCore(hostContext.Configuration)
//自定义日志下发包
.ReplaceDownlinkPacket<JT808DownlinkPacketLogging>()
//自定义会话通知(在线/离线)使用异步方式
//.ReplaceSessionPublishing<CustomJT808SessionPublishing>()
//自定义原包转发 使用异步方式
//.ReplaceSourcePackageDispatcher<CustomJT808SourcePackageDispatcher>
.AddJT808TcpNettyHost()
// 自定义Tcp消息处理业务
.ReplaceMsgIdHandler<JT808MsgIdTcpCustomHandler>()
.Builder()
.AddJT808UdpNettyHost()
// 自定义Udp消息处理业务
.ReplaceMsgIdHandler<JT808MsgIdUdpCustomHandler>()
.Builder()
.AddJT808WebApiNettyHost()
.Builder();
//webapi客户端调用
services.AddHttpApi<IJT808DotNettyWebApi>().ConfigureHttpApiConfig((c, p) =>
{
c.HttpHost = new Uri("http://localhost:828/jt808api/");
c.FormatOptions.DateTimeFormat = "yyyy-MM-dd HH:mm:ss.fff";
c.LoggerFactory = p.GetRequiredService<ILoggerFactory>();
});
var client = services.BuildServiceProvider().GetRequiredService<IJT808DotNettyWebApi>();
var result = client.GetTcpAtomicCounter().InvokeAsync().Result;
});

await serverHostBuilder.RunConsoleAsync();
}
```

如图所示:
![demo1](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/demo1.png)

## 举个栗子2

1.拉取JT808子模块

2.打开项目进行还原编译生成

3.进入JT808.DotNetty.SimpleServer项目下的Debug目录运行服务端

4.进入JT808.DotNetty.SimpleClient项目下的Debug目录运行客户端

如图所示:
![demo2](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/demo2.png)

+ 512
- 0
api/README.md 查看文件

@@ -0,0 +1,512 @@
# JT808 WebApi服务

基地址:127.0.0.1:828/jt808api/

> 注意url格式

数据格式:只支持Json格式

默认端口:828

## 1.统一下发设备消息服务

[基于Tcp统一下发设备消息服务](#tcp_send)

[基于Udp统一下发设备消息服务](#udp_send)

## 2.管理会话服务

[基于Tcp管理会话服务](#tcp_session)

[基于Udp管理会话服务](#udp_session)

## 3.转发地址过滤服务

[基于Tcp转发地址过滤服务](#tcp_transmit)

## 4.消息包计数服务(次日清零)

[基于Tcp消息包计数服务](#tcp_counter)

[基于Udp消息包计数服务](#udp_counter)

## 5.流量统计服务(次日清零)

[基于Tcp流量统计服务](#tcp_traffic)

[基于Udp流量统计服务](#udp_traffic)

## 6.系统性能数据采集服务

[获取当前系统进程使用率](#system_collect)

## 接口请求对照表

### 基于Tcp接口请求

|请求Url|请求方式|说明|
|:------|:------|:------|
| 127.0.0.1:828/jt808api/Tcp/UnificationSend| POST| 基于Tcp统一下发设备消息服务|
| 127.0.0.1:828/jt808api/Tcp/Session/GetAll| GET| 基于Tcp管理会话服务-获取会话集合|
| 127.0.0.1:828/jt808api/Tcp/Session/RemoveByTerminalPhoneNo| POST| 基于Tcp管理会话服务-通过设备终端号移除对应会话|
| 127.0.0.1:828/jt808api/Tcp/Transmit/Add| POST| 基于Tcp转发地址过滤服务-添加转发过滤地址|
| 127.0.0.1:828/jt808api/Tcp/Transmit/Remove| POST| 基于Tcp转发地址过滤服务-删除转发过滤地址|
| 127.0.0.1:828/jt808api/Tcp/Transmit/GetAll| GET| 基于Tcp转发地址过滤服务-获取转发过滤地址信息集合|
| 127.0.0.1:828/jt808api/Tcp/GetAtomicCounter| GET| 基于Tcp消息包计数服务|
| 127.0.0.1:828/jt808api/Tcp/Traffic/Get| GET| 基于Tcp流量统计服务|

### 基于Udp接口请求

|请求Url|请求方式|说明|
|:------|:------|:------|
| 127.0.0.1:828/jt808api/Udp/UnificationSend| POST| 基于Udp统一下发设备消息服务|
| 127.0.0.1:828/jt808api/Udp/Session/GetAll| GET| 基于Udp管理会话服务-获取会话集合|
| 127.0.0.1:828/jt808api/Udp/Session/RemoveByTerminalPhoneNo| POST| 基于Udp管理会话服务-通过设备终端号移除对应会话|
| 127.0.0.1:828/jt808api/Udp/GetAtomicCounter| GET| 基于Udp消息包计数服务|
| 127.0.0.1:828/jt808api/Udp/Traffic/Get| GET| 基于Udp流量统计服务|

### 公共接口请求

|请求Url|请求方式|说明|
|:------|:------|:------|
| 127.0.0.1:828/jt808api/SystemCollect/Get| GET| 获取当前系统进程使用情况|

### 统一对象返回 JT808ResultDto\<T>

|属性|数据类型|参数说明|
|:------:|:------:|:------|
| Message| string| 消息描述|
| Code| int| 状态码|
| Data| T(泛型)| 数据|

返回Code[状态码]说明:

|状态码|说明|
|:------:|:------:|
| 200 | 返回成功 |
| 201 | 内容为空 |
| 404 | 没有该服务 |
| 500 | 服务内部错误 |

### <span id="tcp_send">基于Tcp统一下发设备消息服务</span>

请求地址:Tcp/UnificationSend

请求方式:POST

请求参数:

|属性|数据类型|参数说明|
|------|:------:|:------|
| TerminalPhoneNo| string| 设备终端号|
| Data| byte[]| JT808 byte[]数组|

返回数据:

|属性|数据类型|参数说明|
|:------:|:------:|:------|
| Data| bool| 是否成功|

返回结果:

``` result1
{
"Message":"",
"Code":200,
"Data":true
}
```

### <span id="udp_send">基于Udp统一下发设备消息服务</span>

请求地址:Udp/UnificationSend

请求方式:POST

请求参数:

|属性|数据类型|参数说明|
|------|:------:|:------|
| TerminalPhoneNo| string| 设备终端号|
| Data| byte[]| JT808 byte[]数组|

返回数据:

|属性|数据类型|参数说明|
|:------:|:------:|:------|
| Data| bool| 是否成功|

返回结果:

``` result1
{
"Message":"",
"Code":200,
"Data":true
}
```

### <span id="tcp_session">基于Tcp管理会话服务</span>

#### 统一会话信息对象返回 JT808TcpSessionInfoDto

|属性|数据类型|参数说明|
|------|------|------|
| LastActiveTime| DateTime| 最后上线时间|
| StartTime| DateTime| 上线时间|
| TerminalPhoneNo|string| 终端手机号|
| RemoteAddressIP| string| 远程ip地址|

#### 1.获取会话集合

请求地址:Tcp/Session/GetAll

请求方式:GET

返回数据:

|属性|数据类型|参数说明|
|:------:|:------:|:------|
| Data| List\<JT808TcpSessionInfoDto> | 实际会话信息集合 |

返回结果:

``` session1
{
"Message":"",
"Code":200,
"Data":[
{
"LastActiveTime":"2018-11-27 20:00:00",
"StartTime":"2018-11-25 20:00:00",
"TerminalPhoneNo":"123456789012",
"RemoteAddressIP":"127.0.0.1:11808"
},{
"LastActiveTime":"2018-11-27 20:00:00",
"StartTime":"2018-11-25 20:00:00",
"TerminalPhoneNo":"123456789013",
"RemoteAddressIP":"127.0.0.1:11808"
}
]
}
```

#### 2.通过设备终端号移除对应会话

请求地址:Tcp/Session/RemoveByTerminalPhoneNo

请求方式:POST

请求参数:

|属性|数据类型|参数说明|
|:------:|:------:|:------|
| terminalPhoneNo| string| 设备终端号|

返回数据:

|属性|数据类型|参数说明|
|:------:|:------:|:------|
| Data| bool | 是否成功

返回结果:

``` session3
{
"Message":"",
"Code":200,
"Data":true
}
```

### <span id="udp_session">基于Udp管理会话服务</span>

#### 统一会话信息对象返回 JT808UdpSessionInfoDto

|属性|数据类型|参数说明|
|------|------|------|
| LastActiveTime| DateTime| 最后上线时间|
| StartTime| DateTime| 上线时间|
| TerminalPhoneNo|string| 终端手机号|
| RemoteAddressIP| string| 远程ip地址|

#### 1.获取会话集合

请求地址:Udp/Session/GetAll

请求方式:GET

返回数据:

|属性|数据类型|参数说明|
|:------:|:------:|:------|
| Data| List\<JT808UdpSessionInfoDto> | 实际会话信息集合 |

返回结果:

``` session1
{
"Message":"",
"Code":200,
"Data":[
{
"LastActiveTime":"2018-11-27 20:00:00",
"StartTime":"2018-11-25 20:00:00",
"TerminalPhoneNo":"123456789012",
"RemoteAddressIP":"127.0.0.1:11808"
},{
"LastActiveTime":"2018-11-27 20:00:00",
"StartTime":"2018-11-25 20:00:00",
"TerminalPhoneNo":"123456789013",
"RemoteAddressIP":"127.0.0.1:11808"
}
]
}
```

#### 2.通过设备终端号移除对应会话

请求地址:Udp/Session/RemoveByTerminalPhoneNo

请求方式:POST

请求参数:

|属性|数据类型|参数说明|
|:------:|:------:|:------|
| terminalPhoneNo| string| 设备终端号|

返回数据:

|属性|数据类型|参数说明|
|:------:|:------:|:------|
| Data| bool | 是否成功

返回结果:

``` session3
{
"Message":"",
"Code":200,
"Data":true
}
```

### <span id="tcp_transmit">基于Tcp转发地址过滤服务</span>

#### 1.添加转发过滤地址

请求地址:Tcp/Transmit/Add

请求方式:POST

请求参数:

|属性|数据类型|参数说明|
|:------:|:------:|:------|
| Host| string| ip地址|
| Port| int| 端口号|

返回数据:

|属性|数据类型|参数说明|
|:------:|:------:|:------|
| Data| bool | 是否成功

返回结果:

``` tr1
{
"Message":"",
"Code":200,
"Data":true
}
```

#### 2.删除转发过滤地址(不能删除在网关服务器配置文件配的地址)

请求地址:Tcp/Transmit/Remove

请求方式:POST

请求参数:

|属性|数据类型|参数说明|
|:------:|:------:|:------|
| Host| string| ip地址|

返回数据:

|属性|数据类型|参数说明|
|:------:|:------:|:------|
| Data| bool | 是否成功|

返回结果:

``` tr2
{
"Message":"",
"Code":200,
"Data":true
}
```

#### 3.获取转发过滤地址信息集合

请求地址:Tcp/Transmit/GetAll

请求方式:GET

返回数据:

|属性|数据类型|参数说明|
|------|:------:|:------|
| Data| List\<string> | 远程ip地址(不加端口号)|

返回结果:

``` tr3
{
"Message":"",
"Code":200,
"Data":[
"127.0.0.1"
]
}
```

### <span id="tcp_counter">基于Tcp消息包计数服务</span>

请求地址:Tcp/GetAtomicCounter

请求方式:GET

返回数据:

|属性|数据类型|参数说明|
|------|:------:|:------|
| MsgSuccessCount| long| 消息包成功数|
| MsgFailCount| long| 消息包失败数|

返回结果:

``` counter
{
"Message":"",
"Code":200,
"Data":{
"MsgSuccessCount":10000,
"MsgFailCount":0
}
}
```

### <span id="udp_counter">基于Udp消息包计数服务</span>

请求地址:Udp/GetAtomicCounter

请求方式:GET

返回数据:

|属性|数据类型|参数说明|
|------|:------:|:------|
| MsgSuccessCount| long| 消息包成功数|
| MsgFailCount| long| 消息包失败数|

返回结果:

``` counter
{
"Message":"",
"Code":200,
"Data":{
"MsgSuccessCount":1000,
"MsgFailCount":0
}
}
```

### <span id="tcp_traffic">基于Tcp流量统计服务</span>

请求地址:Tcp/Traffic/Get

请求方式:GET

返回数据:

|属性|数据类型|参数说明|
|------|:------:|:------|
| TotalReceiveSize| double| 总接收大小(单位KB)|
| TotalSendSize| double| 总发送大小(单位KB)|

返回结果:

``` traffic1
{
"Message":"",
"Code":200,
"Data":{
"TotalReceiveSize":0.0478515625,
"TotalSendSize":0.01953125
}
}
```

### <span id="udp_traffic">基于Udp流量统计服务</span>

请求地址:Udp/Traffic/Get

请求方式:GET

返回数据:

|属性|数据类型|参数说明|
|------|:------:|:------|
| TotalReceiveSize| double| 总接收大小(单位KB)|
| TotalSendSize| double| 总发送大小(单位KB)|

返回结果:

``` traffic2
{
"Message":"",
"Code":200,
"Data":{
"TotalReceiveSize":0.0478515625,
"TotalSendSize":0.01953125
}
}
```

### <span id="system_collect">系统性能数据采集服务</span>

请求地址:SystemCollect/Get

请求方式:GET

返回数据:

|属性|数据类型|参数说明|
|------|:------:|:------|
| ProcessId| int| 进程Id|
| WorkingSet64| double| 进程分配内存(单位MB)|
| PeakWorkingSet64| double| 进程分配内存峰值(单位MB)|
| PrivateMemorySize64| double| 进程分配私有内存(单位MB)|
| CPUTotalProcessorTime| TimeSpan|进程执行CPU总处理时间|

返回结果:

``` sc
{
"Message":"",
"Code":200,
"Data":{
"ProcessId":101412,
"WorkingSet64":73.0625,
"PeakWorkingSet64":73.0625,
"PrivateMemorySize64":134.6796875,
"CPUTotalProcessorTime":"00:00:14.5625000"
}
}
```

+ 16
- 0
doc/README.md 查看文件

@@ -0,0 +1,16 @@
## 压力测试

[感谢泥水佬提供的压力测试工具](https://www.cnblogs.com/smark/p/4496660.html?utm_source=tuicool)

| 操作系统 | 配置 | 使用 |
|:-------:|:-------:|:-------:|
| win server 2016 | 4c8g | 压力测试客户端 |
| centos7 | 4c8g | JT808服务端 |

![performance_1000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/performance_1000.png)

![performance_2000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/performance_2000.png)

![performance_5000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/performance_5000.png)

![performance_10000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/performance_10000.png)

二进制
doc/img/demo1.png 查看文件

之前 之后
宽度: 1198  |  高度: 731  |  大小: 44 KiB

二进制
doc/img/demo2.png 查看文件

之前 之后
宽度: 1687  |  高度: 610  |  大小: 108 KiB

二进制
doc/img/design_model.png 查看文件

之前 之后
宽度: 719  |  高度: 431  |  大小: 41 KiB

二进制
doc/img/performance_1000.png 查看文件

之前 之后
宽度: 957  |  高度: 676  |  大小: 130 KiB

二进制
doc/img/performance_10000.png 查看文件

之前 之后
宽度: 962  |  高度: 680  |  大小: 156 KiB

二进制
doc/img/performance_2000.png 查看文件

之前 之后
宽度: 964  |  高度: 681  |  大小: 136 KiB

二进制
doc/img/performance_5000.png 查看文件

之前 之后
宽度: 958  |  高度: 683  |  大小: 153 KiB

+ 19
- 0
simples/JT808.DotNetty.SimpleClient/JT808.DotNetty.SimpleClient.csproj 查看文件

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

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
<LangVersion>7.3</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.2.0" />
<PackageReference Include="WebApiClient.Extensions.DependencyInjection" Version="1.2.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\JT808.DotNetty.Client\JT808.DotNetty.Client.csproj" />
</ItemGroup>

</Project>

+ 38
- 0
simples/JT808.DotNetty.SimpleClient/Program.cs 查看文件

@@ -0,0 +1,38 @@
using JT808.DotNetty.Client;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using JT808.Protocol.MessageBody;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using Microsoft.Extensions.Hosting;
using JT808.DotNetty.SimpleClient.Services;

namespace JT808.DotNetty.SimpleClient
{
class Program
{
static async Task Main(string[] args)
{
var serverHostBuilder = new HostBuilder()
.ConfigureLogging((context, logging) =>
{
logging.AddConsole();
logging.SetMinimumLevel(LogLevel.Trace);
})
.ConfigureServices((hostContext, services) =>
{
services.AddSingleton<ILoggerFactory, LoggerFactory>();
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
services.AddLogging(options => {
options.AddConsole();
options.SetMinimumLevel(LogLevel.Trace);
});
services.AddJT808Client();
services.AddHostedService<UpService>();
});
await serverHostBuilder.RunConsoleAsync();
}
}
}

+ 68
- 0
simples/JT808.DotNetty.SimpleClient/Services/UpService.cs 查看文件

@@ -0,0 +1,68 @@
using JT808.DotNetty.Client;
using JT808.Protocol.MessageBody;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace JT808.DotNetty.SimpleClient.Services
{
public class UpService : IHostedService
{
private readonly IJT808TcpClientFactory jT808TcpClientFactory;

public UpService(IJT808TcpClientFactory jT808TcpClientFactory)
{
this.jT808TcpClientFactory = jT808TcpClientFactory;
}

public Task StartAsync(CancellationToken cancellationToken)
{
JT808TcpClient client1 = jT808TcpClientFactory.Create(new DeviceConfig("12345678910", "127.0.0.1", 12808));
//1.终端注册
client1.Send(new JT808_0x0100()
{
PlateNo = "粤A12345",
PlateColor = 2,
AreaID = 0,
CityOrCountyId = 0,
MakerId = "Koike001",
TerminalId = "Koike001",
TerminalModel = "Koike001"
});
//2.终端鉴权
client1.Send(new JT808_0x0102()
{
Code = "1234"
});
Task.Run(() => {
while (true)
{
var i = 0;
//3.每30秒发一次
client1.Send(new JT808_0x0200()
{
Lat = 110000 + i,
Lng = 100000 + i,
GPSTime = DateTime.Now,
Speed = 50,
Direction = 30,
AlarmFlag = 5,
Altitude = 50,
StatusFlag = 10
});
i++;
Thread.Sleep(30000);
}
});
return Task.CompletedTask;
}

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

+ 59
- 0
simples/JT808.DotNetty.SimpleServer/Handlers/JT808MsgIdTcpSimpleHandler.cs 查看文件

@@ -0,0 +1,59 @@
using JT808.DotNetty.Core;
using JT808.DotNetty.Core.Handlers;
using JT808.DotNetty.Core.Interfaces;
using JT808.DotNetty.Core.Metadata;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT808.DotNetty.SimpleServer.Handlers
{
public class JT808MsgIdTcpSimpleHandler : JT808MsgIdTcpHandlerBase
{
public JT808MsgIdTcpSimpleHandler(
ILoggerFactory loggerFactory,
JT808TcpSessionManager sessionManager) : base(sessionManager)
{
logger = loggerFactory.CreateLogger<JT808MsgIdTcpSimpleHandler>();
}

private readonly ILogger<JT808MsgIdTcpSimpleHandler> logger;

public override IJT808Reply Msg0x0200(JT808Request request)
{
logger.LogDebug("Tcp_Msg0x0200");
return base.Msg0x0200(request);
}

public override IJT808Reply Msg0x0001(JT808Request request)
{
logger.LogDebug("Tcp_Msg0x0001");
return base.Msg0x0001(request);
}

public override IJT808Reply Msg0x0002(JT808Request request)
{
logger.LogDebug("Tcp_Msg0x0002");
return base.Msg0x0002(request);
}

public override IJT808Reply Msg0x0003(JT808Request request)
{
logger.LogDebug("Tcp_Msg0x0003");
return base.Msg0x0003(request);
}

public override IJT808Reply Msg0x0100(JT808Request request)
{
logger.LogDebug("Tcp_Msg0x0100");
return base.Msg0x0100(request);
}

public override IJT808Reply Msg0x0102(JT808Request request)
{
logger.LogDebug("Tcp_Msg0x0102");
return base.Msg0x0102(request);
}
}
}

+ 25
- 0
simples/JT808.DotNetty.SimpleServer/JT808.DotNetty.SimpleServer.csproj 查看文件

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

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
<LangVersion>7.3</LangVersion>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\JT808.DotNetty.Tcp\JT808.DotNetty.Tcp.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.2.0" />
<PackageReference Include="WebApiClient.Extensions.DependencyInjection" Version="1.2.3" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>

+ 47
- 0
simples/JT808.DotNetty.SimpleServer/Program.cs 查看文件

@@ -0,0 +1,47 @@

using JT808.DotNetty.Core;
using JT808.DotNetty.Core.Handlers;
using JT808.DotNetty.SimpleServer.Handlers;
using JT808.DotNetty.Tcp;
using JT808.Protocol;
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;

namespace JT808.DotNetty.SimpleServer
{
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.AddJT808Configure()
.AddJT808NettyCore(hostContext.Configuration)
.AddJT808TcpNettyHost()
// 自定义Tcp消息处理业务
.ReplaceMsgIdHandler<JT808MsgIdTcpSimpleHandler>()
.Builder();
});

await serverHostBuilder.RunConsoleAsync();
}
}
}

+ 125
- 0
simples/JT808.DotNetty.Simples.sln 查看文件

@@ -0,0 +1,125 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.168
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B5A80356-5AF6-449F-9D8B-3C1BBB9D2443}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Protocol", "..\src\JT808.Protocol\src\JT808.Protocol\JT808.Protocol.csproj", "{9FCA2EE9-8253-41AA-A64C-9883413864F9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.Udp", "..\src\JT808.DotNetty.Udp\JT808.DotNetty.Udp.csproj", "{C960084C-2CF4-4748-AD35-D2384285D6A3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.Core", "..\src\JT808.DotNetty.Core\JT808.DotNetty.Core.csproj", "{67C5DC72-0004-48B3-BB5A-9CB7069B4F02}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.Abstractions", "..\src\JT808.DotNetty.Abstractions\JT808.DotNetty.Abstractions.csproj", "{4DCF33C0-67C5-4179-AF1E-4E919F9F856D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{3BD7FF02-8516-4A77-A385-9FDCDD792E22}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.Tcp", "..\src\JT808.DotNetty.Tcp\JT808.DotNetty.Tcp.csproj", "{330CD783-5564-4083-ABFC-573CDC369F50}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.WebApi", "..\src\JT808.DotNetty.WebApi\JT808.DotNetty.WebApi.csproj", "{B783DE53-CE2A-4225-921F-04E5E57B28F3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.Core.Test", "..\src\JT808.DotNetty.Tests\JT808.DotNetty.Core.Test\JT808.DotNetty.Core.Test.csproj", "{1C4CCE9B-761B-4581-B5DA-5B6D83572D56}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.Tcp.Test", "..\src\JT808.DotNetty.Tests\JT808.DotNetty.Tcp.Test\JT808.DotNetty.Tcp.Test.csproj", "{AEF1E1E2-C861-4268-86F6-6F376FAF79A7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.Udp.Test", "..\src\JT808.DotNetty.Tests\JT808.DotNetty.Udp.Test\JT808.DotNetty.Udp.Test.csproj", "{E503BFD8-D90A-4610-97C7-5B9A0497303B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.WebApi.Test", "..\src\JT808.DotNetty.Tests\JT808.DotNetty.WebApi.Test\JT808.DotNetty.WebApi.Test.csproj", "{EDE77A29-0840-450C-8B08-2D3388845AE5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.Hosting", "..\src\JT808.DotNetty.Tests\JT808.DotNetty.Hosting\JT808.DotNetty.Hosting.csproj", "{A0F2F006-5AEB-454E-83C5-ABFB58DE17A9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.WebApiClientTool", "..\src\JT808.DotNetty.WebApiClientTool\JT808.DotNetty.WebApiClientTool.csproj", "{9D86C951-94F2-4CBD-B177-8AF31DDB05D8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.Client", "..\src\JT808.DotNetty.Client\JT808.DotNetty.Client.csproj", "{87C08239-C57F-4FC5-9579-05D0723AA4A0}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "simples", "simples", "{2459FB59-8A33-49A4-ADBC-A0B12C5886A6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.SimpleClient", "JT808.DotNetty.SimpleClient\JT808.DotNetty.SimpleClient.csproj", "{E6F61CE8-BFB4-4946-A0D3-AECCE77824E5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.DotNetty.SimpleServer", "JT808.DotNetty.SimpleServer\JT808.DotNetty.SimpleServer.csproj", "{CCE6AEFB-1AB0-4BD9-8EA2-8B4CDD097E88}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9FCA2EE9-8253-41AA-A64C-9883413864F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9FCA2EE9-8253-41AA-A64C-9883413864F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9FCA2EE9-8253-41AA-A64C-9883413864F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9FCA2EE9-8253-41AA-A64C-9883413864F9}.Release|Any CPU.Build.0 = Release|Any CPU
{C960084C-2CF4-4748-AD35-D2384285D6A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C960084C-2CF4-4748-AD35-D2384285D6A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C960084C-2CF4-4748-AD35-D2384285D6A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C960084C-2CF4-4748-AD35-D2384285D6A3}.Release|Any CPU.Build.0 = Release|Any CPU
{67C5DC72-0004-48B3-BB5A-9CB7069B4F02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{67C5DC72-0004-48B3-BB5A-9CB7069B4F02}.Debug|Any CPU.Build.0 = Debug|Any CPU
{67C5DC72-0004-48B3-BB5A-9CB7069B4F02}.Release|Any CPU.ActiveCfg = Release|Any CPU
{67C5DC72-0004-48B3-BB5A-9CB7069B4F02}.Release|Any CPU.Build.0 = Release|Any CPU
{4DCF33C0-67C5-4179-AF1E-4E919F9F856D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4DCF33C0-67C5-4179-AF1E-4E919F9F856D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4DCF33C0-67C5-4179-AF1E-4E919F9F856D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4DCF33C0-67C5-4179-AF1E-4E919F9F856D}.Release|Any CPU.Build.0 = Release|Any CPU
{330CD783-5564-4083-ABFC-573CDC369F50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{330CD783-5564-4083-ABFC-573CDC369F50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{330CD783-5564-4083-ABFC-573CDC369F50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{330CD783-5564-4083-ABFC-573CDC369F50}.Release|Any CPU.Build.0 = Release|Any CPU
{B783DE53-CE2A-4225-921F-04E5E57B28F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B783DE53-CE2A-4225-921F-04E5E57B28F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B783DE53-CE2A-4225-921F-04E5E57B28F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B783DE53-CE2A-4225-921F-04E5E57B28F3}.Release|Any CPU.Build.0 = Release|Any CPU
{1C4CCE9B-761B-4581-B5DA-5B6D83572D56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1C4CCE9B-761B-4581-B5DA-5B6D83572D56}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1C4CCE9B-761B-4581-B5DA-5B6D83572D56}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1C4CCE9B-761B-4581-B5DA-5B6D83572D56}.Release|Any CPU.Build.0 = Release|Any CPU
{AEF1E1E2-C861-4268-86F6-6F376FAF79A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AEF1E1E2-C861-4268-86F6-6F376FAF79A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AEF1E1E2-C861-4268-86F6-6F376FAF79A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AEF1E1E2-C861-4268-86F6-6F376FAF79A7}.Release|Any CPU.Build.0 = Release|Any CPU
{E503BFD8-D90A-4610-97C7-5B9A0497303B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E503BFD8-D90A-4610-97C7-5B9A0497303B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E503BFD8-D90A-4610-97C7-5B9A0497303B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E503BFD8-D90A-4610-97C7-5B9A0497303B}.Release|Any CPU.Build.0 = Release|Any CPU
{EDE77A29-0840-450C-8B08-2D3388845AE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EDE77A29-0840-450C-8B08-2D3388845AE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EDE77A29-0840-450C-8B08-2D3388845AE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EDE77A29-0840-450C-8B08-2D3388845AE5}.Release|Any CPU.Build.0 = Release|Any CPU
{A0F2F006-5AEB-454E-83C5-ABFB58DE17A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A0F2F006-5AEB-454E-83C5-ABFB58DE17A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A0F2F006-5AEB-454E-83C5-ABFB58DE17A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A0F2F006-5AEB-454E-83C5-ABFB58DE17A9}.Release|Any CPU.Build.0 = Release|Any CPU
{9D86C951-94F2-4CBD-B177-8AF31DDB05D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9D86C951-94F2-4CBD-B177-8AF31DDB05D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9D86C951-94F2-4CBD-B177-8AF31DDB05D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9D86C951-94F2-4CBD-B177-8AF31DDB05D8}.Release|Any CPU.Build.0 = Release|Any CPU
{87C08239-C57F-4FC5-9579-05D0723AA4A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{87C08239-C57F-4FC5-9579-05D0723AA4A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{87C08239-C57F-4FC5-9579-05D0723AA4A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{87C08239-C57F-4FC5-9579-05D0723AA4A0}.Release|Any CPU.Build.0 = Release|Any CPU
{E6F61CE8-BFB4-4946-A0D3-AECCE77824E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E6F61CE8-BFB4-4946-A0D3-AECCE77824E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E6F61CE8-BFB4-4946-A0D3-AECCE77824E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E6F61CE8-BFB4-4946-A0D3-AECCE77824E5}.Release|Any CPU.Build.0 = Release|Any CPU
{CCE6AEFB-1AB0-4BD9-8EA2-8B4CDD097E88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CCE6AEFB-1AB0-4BD9-8EA2-8B4CDD097E88}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CCE6AEFB-1AB0-4BD9-8EA2-8B4CDD097E88}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CCE6AEFB-1AB0-4BD9-8EA2-8B4CDD097E88}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{9FCA2EE9-8253-41AA-A64C-9883413864F9} = {B5A80356-5AF6-449F-9D8B-3C1BBB9D2443}
{1C4CCE9B-761B-4581-B5DA-5B6D83572D56} = {3BD7FF02-8516-4A77-A385-9FDCDD792E22}
{AEF1E1E2-C861-4268-86F6-6F376FAF79A7} = {3BD7FF02-8516-4A77-A385-9FDCDD792E22}
{E503BFD8-D90A-4610-97C7-5B9A0497303B} = {3BD7FF02-8516-4A77-A385-9FDCDD792E22}
{EDE77A29-0840-450C-8B08-2D3388845AE5} = {3BD7FF02-8516-4A77-A385-9FDCDD792E22}
{A0F2F006-5AEB-454E-83C5-ABFB58DE17A9} = {3BD7FF02-8516-4A77-A385-9FDCDD792E22}
{E6F61CE8-BFB4-4946-A0D3-AECCE77824E5} = {2459FB59-8A33-49A4-ADBC-A0B12C5886A6}
{CCE6AEFB-1AB0-4BD9-8EA2-8B4CDD097E88} = {2459FB59-8A33-49A4-ADBC-A0B12C5886A6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FC0FFCEA-E1EF-4C97-A1C5-F89418B6834B}
EndGlobalSection
EndGlobal

+ 12
- 0
src/JT808.DotNetty.Abstractions/Dtos/JT808AtomicCounterDto.cs 查看文件

@@ -0,0 +1,12 @@
namespace JT808.DotNetty.Abstractions.Dtos
{
/// <summary>
/// 包计数器服务
/// </summary>
public class JT808AtomicCounterDto
{
public long MsgSuccessCount { get; set; }

public long MsgFailCount { get; set; }
}
}

+ 15
- 0
src/JT808.DotNetty.Abstractions/Dtos/JT808DefaultResultDto.cs 查看文件

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

namespace JT808.DotNetty.Abstractions.Dtos
{
public class JT808DefaultResultDto: JT808ResultDto<string>
{
public JT808DefaultResultDto()
{
Data = "Hello,JT808 WebAPI";
Code = JT808ResultCode.Ok;
}
}
}

+ 37
- 0
src/JT808.DotNetty.Abstractions/Dtos/JT808IPAddressDto.cs 查看文件

@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Runtime.Serialization;
using System.Text;

namespace JT808.DotNetty.Abstractions.Dtos
{
public class JT808IPAddressDto
{
public string Host { get; set; }

public int Port { get; set; }

public EndPoint endPoint;

public EndPoint EndPoint
{
get
{
if (endPoint == null)
{
if (IPAddress.TryParse(Host, out IPAddress ip))
{
endPoint = new IPEndPoint(ip, Port);
}
else
{
endPoint = new DnsEndPoint(Host, Port);
}
}
return endPoint;
}
set { }
}
}
}

+ 29
- 0
src/JT808.DotNetty.Abstractions/Dtos/JT808ResultDto.cs 查看文件

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

namespace JT808.DotNetty.Abstractions.Dtos
{
public class JT808ResultDto<T>
{
public JT808ResultDto()
{
Code = JT808ResultCode.Ok;
}

public string Message { get; set; }

public int Code { get; set; }

public T Data { get; set; }
}

public class JT808ResultCode
{
public const int Ok = 200;
public const int Empty = 201;
public const int NotFound = 404;
public const int Fail = 400;
public const int Error = 500;
}
}

+ 33
- 0
src/JT808.DotNetty.Abstractions/Dtos/JT808SystemCollectInfoDto.cs 查看文件

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

namespace JT808.DotNetty.Abstractions.Dtos
{
public class JT808SystemCollectInfoDto
{
/// <summary>
/// 进程Id
/// </summary>
public int ProcessId { get; set; }
/// <summary>
/// 进程分配内存
/// 单位MB
/// </summary>
public double WorkingSet64 { get; set; }
/// <summary>
/// 进程分配内存峰值
/// 单位MB
/// </summary>
public double PeakWorkingSet64 { get; set; }
/// <summary>
/// 进程分配私有内存
/// 单位MB
/// </summary>
public double PrivateMemorySize64 { get; set; }
/// <summary>
/// 进程执行CPU总处理时间
/// </summary>
public TimeSpan CPUTotalProcessorTime { get; set; }
}
}

+ 24
- 0
src/JT808.DotNetty.Abstractions/Dtos/JT808TcpSessionInfoDto.cs 查看文件

@@ -0,0 +1,24 @@
using System;

namespace JT808.DotNetty.Abstractions.Dtos
{
public class JT808TcpSessionInfoDto
{
/// <summary>
/// 最后上线时间
/// </summary>
public DateTime LastActiveTime { get; set; }
/// <summary>
/// 上线时间
/// </summary>
public DateTime StartTime { get; set; }
/// <summary>
/// 终端手机号
/// </summary>
public string TerminalPhoneNo { get; set; }
/// <summary>
/// 远程ip地址
/// </summary>
public string RemoteAddressIP { get; set; }
}
}

+ 20
- 0
src/JT808.DotNetty.Abstractions/Dtos/JT808TrafficInfoDto.cs 查看文件

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

namespace JT808.DotNetty.Abstractions.Dtos
{
public class JT808TrafficInfoDto
{
/// <summary>
/// 总接收大小
/// 单位KB
/// </summary>
public double TotalReceiveSize { get; set; }
/// <summary>
/// 总发送大小
/// 单位KB
/// </summary>
public double TotalSendSize { get; set; }
}
}

+ 24
- 0
src/JT808.DotNetty.Abstractions/Dtos/JT808UdpSessionInfoDto.cs 查看文件

@@ -0,0 +1,24 @@
using System;

namespace JT808.DotNetty.Abstractions.Dtos
{
public class JT808UdpSessionInfoDto
{
/// <summary>
/// 最后上线时间
/// </summary>
public DateTime LastActiveTime { get; set; }
/// <summary>
/// 上线时间
/// </summary>
public DateTime StartTime { get; set; }
/// <summary>
/// 终端手机号
/// </summary>
public string TerminalPhoneNo { get; set; }
/// <summary>
/// 远程ip地址
/// </summary>
public string RemoteAddressIP { get; set; }
}
}

+ 11
- 0
src/JT808.DotNetty.Abstractions/Dtos/JT808UnificationSendRequestDto.cs 查看文件

@@ -0,0 +1,11 @@
namespace JT808.DotNetty.Abstractions.Dtos
{
/// <summary>
/// 统一下发请求参数
/// </summary>
public class JT808UnificationSendRequestDto
{
public string TerminalPhoneNo { get; set; }
public byte[] Data { get; set; }
}
}

+ 15
- 0
src/JT808.DotNetty.Abstractions/Enums/JT808TransportProtocolType.cs 查看文件

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

namespace JT808.DotNetty.Abstractions.Enums
{
/// <summary>
/// 传输协议类型
/// </summary>
public enum JT808TransportProtocolType
{
tcp=1,
udp = 2
}
}

+ 22
- 0
src/JT808.DotNetty.Abstractions/IJT808DownlinkPacket.cs 查看文件

@@ -0,0 +1,22 @@
using JT808.DotNetty.Abstractions.Enums;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace JT808.DotNetty.Abstractions
{
/// <summary>
/// 下行数据包处理接口
/// </summary>
public interface IJT808DownlinkPacket
{
/// <summary>
///
/// </summary>
/// <param name="data">数据包</param>
/// <param name="protocolType">协议类型:tcp/udp</param>
/// <returns></returns>
Task ProcessorAsync(byte[] data, JT808TransportProtocolType transportProtocolType);
}
}

+ 12
- 0
src/JT808.DotNetty.Abstractions/IJT808SessionPublishing.cs 查看文件

@@ -0,0 +1,12 @@
using System.Threading.Tasks;

namespace JT808.DotNetty.Abstractions
{
/// <summary>
/// 会话通知(在线/离线)
/// </summary>
public interface IJT808SessionPublishing
{
Task PublishAsync(string topicName, string value);
}
}

+ 15
- 0
src/JT808.DotNetty.Abstractions/IJT808SourcePackageDispatcher.cs 查看文件

@@ -0,0 +1,15 @@
using System.Threading.Tasks;

namespace JT808.DotNetty.Abstractions
{
/// <summary>
/// 源包分发器
/// 自定义源包分发器业务
/// ConfigureServices:
/// services.Replace(new ServiceDescriptor(typeof(IJT808SourcePackageDispatcher),typeof(JT808SourcePackageDispatcherDefaultImpl),ServiceLifetime.Singleton));
/// </summary>
public interface IJT808SourcePackageDispatcher
{
Task SendAsync(byte[] data);
}
}

+ 19
- 0
src/JT808.DotNetty.Abstractions/IJT808UplinkPacket.cs 查看文件

@@ -0,0 +1,19 @@
using JT808.DotNetty.Abstractions.Enums;
using System.Threading.Tasks;

namespace JT808.DotNetty.Abstractions
{
/// <summary>
/// 上行数据包处理接口
/// </summary>
public interface IJT808UplinkPacket
{
/// <summary>
///
/// </summary>
/// <param name="data">数据包</param>
/// <param name="transportProtocolType">传输协议类型</param>
/// <returns></returns>
Task ProcessorAsync(byte[] data, JT808TransportProtocolType transportProtocolType);
}
}

+ 10
- 0
src/JT808.DotNetty.Abstractions/JT808.DotNetty.Abstractions.csproj 查看文件

@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\SharedProperties.props" />
<PropertyGroup>
<PackageId>JT808.DotNetty.Abstractions</PackageId>
<Product>JT808.DotNetty.Abstractions</Product>
<Description>基于DotNetty实现的JT808DotNetty的抽象库</Description>
<PackageReleaseNotes>基于DotNetty实现的JT808DotNetty的抽象库</PackageReleaseNotes>
</PropertyGroup>

</Project>

+ 84
- 0
src/JT808.DotNetty.Abstractions/JT808Constants.cs 查看文件

@@ -0,0 +1,84 @@
namespace JT808.DotNetty.Abstractions
{
public static class JT808Constants
{
public const string SessionOnline= "JT808SessionOnline";

public const string SessionOffline = "JT808SessionOffline";

public static class JT808WebApiRouteTable
{
public const string RouteTablePrefix = "/jt808api";

public const string SessionPrefix = "Session";

public const string TransmitPrefix = "Transmit";

public const string SystemCollectPrefix = "SystemCollect";

public const string TrafficPrefix = "Traffic";

public const string TcpPrefix = "Tcp";

public const string UdpPrefix = "Udp";

/// <summary>
///获取当前系统进程使用率
/// </summary>
public static string SystemCollectGet = $"{RouteTablePrefix}/{SystemCollectPrefix}/Get";
/// <summary>
///基于Tcp的添加转发过滤地址
/// </summary>
public static string TransmitAdd = $"{RouteTablePrefix}/{TcpPrefix}/{TransmitPrefix}/Add";
/// <summary>
/// 基于Tcp的删除转发过滤地址(不能删除在网关服务器配置文件配的地址)
/// </summary>
public static string TransmitRemove = $"{RouteTablePrefix}/{TcpPrefix}/{TransmitPrefix}/Remove";
/// <summary>
///基于Tcp的获取转发过滤地址信息集合
/// </summary>
public static string TransmitGetAll = $"{RouteTablePrefix}/{TcpPrefix}/{TransmitPrefix}/GetAll";
/// <summary>
/// 基于Tcp的包计数器
/// </summary>
public static string GetTcpAtomicCounter = $"{RouteTablePrefix}/{TcpPrefix}/GetAtomicCounter";
/// <summary>
/// 基于Tcp的会话服务集合
/// </summary>
public static string SessionTcpGetAll = $"{RouteTablePrefix}/{TcpPrefix}/{SessionPrefix}/GetAll";
/// <summary>
/// 基于Tcp的会话服务-通过设备终端号移除对应会话
/// </summary>
public static string SessionTcpRemoveByTerminalPhoneNo = $"{RouteTablePrefix}/{TcpPrefix}/{SessionPrefix}/RemoveByTerminalPhoneNo";
/// <summary>
/// 基于Tcp的统一下发信息
/// </summary>
public static string UnificationTcpSend = $"{RouteTablePrefix}/{TcpPrefix}/UnificationSend";
/// <summary>
/// 基于Tcp的流量服务获取
/// </summary>
public static string TrafficTcpGet = $"{RouteTablePrefix}/{TcpPrefix}/{TrafficPrefix}/Get";

/// <summary>
/// 获取Udp包计数器
/// </summary>
public static string GetUdpAtomicCounter = $"{RouteTablePrefix}/{UdpPrefix}/GetAtomicCounter";
/// <summary>
/// 基于Udp的统一下发信息
/// </summary>
public static string UnificationUdpSend = $"{RouteTablePrefix}/{UdpPrefix}/UnificationSend";
/// <summary>
/// 基于Udp的会话服务集合
/// </summary>
public static string SessionUdpGetAll = $"{RouteTablePrefix}/{UdpPrefix}/{SessionPrefix}/GetAll";
/// <summary>
/// 基于Udp的会话服务-通过设备终端号移除对应会话
/// </summary>
public static string SessionUdpRemoveByTerminalPhoneNo = $"{RouteTablePrefix}/{UdpPrefix}/{SessionPrefix}/RemoveByTerminalPhoneNo";
/// <summary>
/// 基于Udp的流量服务获取
/// </summary
public static string TrafficUdpGet = $"{RouteTablePrefix}/{UdpPrefix}/{TrafficPrefix}/Get";
}
}
}

+ 13
- 0
src/JT808.DotNetty.Abstractions/Properties/PublishProfiles/FolderProfile.pubxml 查看文件

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<TargetFramework>netstandard2.0</TargetFramework>
<PublishDir>..\..\nupkgs</PublishDir>
</PropertyGroup>
</Project>

+ 6
- 0
src/JT808.DotNetty.Abstractions/Properties/PublishProfiles/FolderProfile.pubxml.user 查看文件

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>

+ 19
- 0
src/JT808.DotNetty.CleintBenchmark/Configs/ClientBenchmarkOptions.cs 查看文件

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

namespace JT808.DotNetty.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;
public ClientBenchmarkOptions Value =>this;
}
}

+ 3106
- 0
src/JT808.DotNetty.CleintBenchmark/Configs/NLog.xsd
文件差异内容过多而无法显示
查看文件


+ 36
- 0
src/JT808.DotNetty.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.DotNetty.Hosting/internalLog.txt"
internalLogLevel="Debug" >
<variable name="Directory" value="/data/logs/JT808.DotNetty.Hosting"/>
<targets>
<target name="all" xsi:type="File"
fileName="${Directory}/all/${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.DotNetty.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/${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>

+ 37
- 0
src/JT808.DotNetty.CleintBenchmark/JT808.DotNetty.CleintBenchmark.csproj 查看文件

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

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
<LangVersion>7.3</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.2.0" />
<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="NLog.Extensions.Logging" Version="1.5.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\JT808.DotNetty.Client\JT808.DotNetty.Client.csproj" />
</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>

</Project>

+ 49
- 0
src/JT808.DotNetty.CleintBenchmark/Program.cs 查看文件

@@ -0,0 +1,49 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging;
using System;
using System.Threading.Tasks;
using JT808.DotNetty.Client;
using JT808.DotNetty.CleintBenchmark.Configs;
using JT808.DotNetty.CleintBenchmark.Services;
using Microsoft.Extensions.Configuration;

namespace JT808.DotNetty.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);
})
.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.AddJT808Client();
services.AddHostedService<CleintBenchmarkHostedService>();
services.AddHostedService<CleintBenchmarkReportHostedService>();
});
await serverHostBuilder.RunConsoleAsync();
}
}
}

+ 83
- 0
src/JT808.DotNetty.CleintBenchmark/Services/CleintBenchmarkHostedService.cs 查看文件

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


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

private readonly ILogger logger;

private readonly IJT808TcpClientFactory jT808TcpClientFactory;

private CancellationTokenSource cts=new CancellationTokenSource();

private TaskFactory taskFactory;

public CleintBenchmarkHostedService(
ILoggerFactory loggerFactory,
IJT808TcpClientFactory jT808TcpClientFactory,
IOptions<ClientBenchmarkOptions> clientBenchmarkOptionsAccessor)
{
this.jT808TcpClientFactory = jT808TcpClientFactory;
clientBenchmarkOptions = clientBenchmarkOptionsAccessor.Value;
logger = loggerFactory.CreateLogger("CleintBenchmarkHostedService");
taskFactory = new TaskFactory();
}
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}");
//ThreadPool.SetMaxThreads(20, 20);
//ThreadPool.GetMaxThreads(out var setMaxWorkerThreads, out var setMaxCompletionPortThreads);
//logger.LogInformation($"SetMaxThreads:{setMaxWorkerThreads}-{setMaxCompletionPortThreads}");
for (int i=0;i< clientBenchmarkOptions.DeviceCount; i++)
{
taskFactory.StartNew((item) =>
{

var client = jT808TcpClientFactory.Create(new DeviceConfig(((int)item).ToString(), clientBenchmarkOptions.IP, clientBenchmarkOptions.Port));
int lat = new Random(1000).Next(100000, 180000);
int Lng = new Random(1000).Next(100000, 180000);
while (!cts.IsCancellationRequested)
{
client.Send(new JT808_0x0200()
{
Lat = lat,
Lng = Lng,
GPSTime = DateTime.Now,
Speed = 50,
Direction = 30,
AlarmFlag = 5,
Altitude = 50,
StatusFlag = 10
});
Thread.Sleep(clientBenchmarkOptions.Interval);
}
}, i,cts.Token);
}
return Task.CompletedTask;
}

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

+ 55
- 0
src/JT808.DotNetty.CleintBenchmark/Services/CleintBenchmarkReportHostedService.cs 查看文件

@@ -0,0 +1,55 @@
using JT808.DotNetty.CleintBenchmark.Configs;
using JT808.DotNetty.Client;
using JT808.DotNetty.Client.Services;
using JT808.Protocol.MessageBody;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;


namespace JT808.DotNetty.CleintBenchmark.Services
{
public class CleintBenchmarkReportHostedService : IHostedService
{
private readonly JT808ReportService jT808ReportService;

private CancellationTokenSource cts=new CancellationTokenSource();

private readonly ILogger logger;
public CleintBenchmarkReportHostedService(
ILoggerFactory loggerFactory,
JT808ReportService jT808ReportService)
{
this.jT808ReportService = jT808ReportService;
logger = loggerFactory.CreateLogger("CleintBenchmarkReportHostedService");
}
public Task StartAsync(CancellationToken cancellationToken)
{
logger.LogInformation("StartAsync...");
Task.Run(() => {
while (!cts.IsCancellationRequested)
{
logger.LogInformation(JsonConvert.SerializeObject(jT808ReportService.JT808Reports.LastOrDefault()));
Thread.Sleep(3000);
}
}, cts.Token);
return Task.CompletedTask;
}

public Task StopAsync(CancellationToken cancellationToken)
{
logger.LogInformation("StopAsync...");
cts.Cancel();
logger.LogInformation("正在生成报表...");
logger.LogInformation(JsonConvert.SerializeObject(jT808ReportService.JT808Reports,Formatting.Indented));
return Task.CompletedTask;
}
}
}

+ 20
- 0
src/JT808.DotNetty.CleintBenchmark/appsettings.json 查看文件

@@ -0,0 +1,20 @@
{
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Trace"
}
},
"Console": {
"LogLevel": {
"Default": "Trace"
}
}
},
"ClientBenchmarkOptions": {
"IP": "127.0.0.1",
"Port": 808,
"DeviceCount": 10
}
}

+ 20
- 0
src/JT808.DotNetty.Client/Codecs/JT808ClientTcpDecoder.cs 查看文件

@@ -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);
}
}
}

+ 54
- 0
src/JT808.DotNetty.Client/Codecs/JT808ClientTcpEncoder.cs 查看文件

@@ -0,0 +1,54 @@
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;
using JT808.DotNetty.Client.Services;
using JT808.Protocol.Interfaces;

namespace JT808.DotNetty.Client.Codecs
{
public class JT808ClientTcpEncoder : MessageToByteEncoder<JT808ClientRequest>
{
private readonly ILogger<JT808ClientTcpEncoder> logger;
private readonly JT808SendAtomicCounterService jT808SendAtomicCounterService;
private readonly JT808Serializer JT808Serializer;

public JT808ClientTcpEncoder(
IJT808Config jT808Config,
JT808SendAtomicCounterService jT808SendAtomicCounterService,ILoggerFactory loggerFactory)
{
logger=loggerFactory.CreateLogger<JT808ClientTcpEncoder>();
this.jT808SendAtomicCounterService = jT808SendAtomicCounterService;
JT808Serializer = jT808Config.GetSerializer();
}

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);
jT808SendAtomicCounterService.MsgSuccessIncrement();
}
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);
jT808SendAtomicCounterService.MsgSuccessIncrement();
}
}
}
}

+ 28
- 0
src/JT808.DotNetty.Client/DeviceConfig.cs 查看文件

@@ -0,0 +1,28 @@
using JT808.Protocol;
using JT808.Protocol.Interfaces;
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 IJT808MsgSNDistributed MsgSNDistributed { get; }
}
}

+ 95
- 0
src/JT808.DotNetty.Client/Handlers/JT808TcpClientConnectionHandler.cs 查看文件

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


+ 30
- 0
src/JT808.DotNetty.Client/Handlers/JT808TcpClientHandler.cs 查看文件

@@ -0,0 +1,30 @@
using DotNetty.Buffers;
using DotNetty.Transport.Channels;
using System;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using JT808.DotNetty.Client.Services;

namespace JT808.DotNetty.Client.Handlers
{
/// <summary>
/// JT808客户端处理程序
/// </summary>
internal class JT808TcpClientHandler : SimpleChannelInboundHandler<byte[]>
{
private readonly ILogger<JT808TcpClientHandler> logger;
private readonly JT808ReceiveAtomicCounterService jT808ReceiveAtomicCounterService;
public JT808TcpClientHandler(JT808ReceiveAtomicCounterService jT808ReceiveAtomicCounterService,JT808TcpClient jT808TcpClient)
{
logger = jT808TcpClient.LoggerFactory.CreateLogger<JT808TcpClientHandler>();
this.jT808ReceiveAtomicCounterService= jT808ReceiveAtomicCounterService;
}

protected override void ChannelRead0(IChannelHandlerContext ctx, byte[] msg)
{
if(logger.IsEnabled(LogLevel.Trace))
logger.LogTrace("accept msg<<<" + ByteBufferUtil.HexDump(msg));
jT808ReceiveAtomicCounterService.MsgSuccessIncrement();
}
}
}

+ 31
- 0
src/JT808.DotNetty.Client/JT808.DotNetty.Client.csproj 查看文件

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

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>7.3</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>
<license>https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE</license>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>2.1.2</Version>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="DotNetty.Handlers" Version="0.6.0" />
<PackageReference Include="DotNetty.Transport.Libuv" Version="0.6.0" />
<PackageReference Include="DotNetty.Codecs" Version="0.6.0" />
<PackageReference Include="JT808" Version="2.1.2" />
<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.2" />
<PackageReference Include="Microsoft.Extensions.Options" Version="2.2.0" />
</ItemGroup>

</Project>

+ 21
- 0
src/JT808.DotNetty.Client/JT808ClientDotnettyExtensions.cs 查看文件

@@ -0,0 +1,21 @@
using JT808.DotNetty.Client.Services;
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<JT808SendAtomicCounterService>();
serviceDescriptors.AddSingleton<JT808ReceiveAtomicCounterService>();
serviceDescriptors.AddSingleton<IJT808TcpClientFactory, JT808TcpClientFactory>();
serviceDescriptors.AddSingleton<JT808ReportService>();
serviceDescriptors.AddHostedService<JT808ReportHostedService>();
return serviceDescriptors;
}
}
}

+ 16
- 0
src/JT808.DotNetty.Client/JT808ClientMsgSNDistributedImpl.cs 查看文件

@@ -0,0 +1,16 @@
using JT808.Protocol;
using JT808.Protocol.Interfaces;
using System.Threading;

namespace JT808.DotNetty.Client
{
internal class JT808ClientMsgSNDistributedImpl : IJT808MsgSNDistributed
{
int _counter = 0;

public ushort Increment()
{
return (ushort)Interlocked.Increment(ref _counter);
}
}
}

+ 116
- 0
src/JT808.DotNetty.Client/JT808TcpClient.cs 查看文件

@@ -0,0 +1,116 @@
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.Runtime.InteropServices;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using System.Net;
using System.Threading.Tasks;
using JT808.DotNetty.Client.Metadata;
using JT808.DotNetty.Client.Codecs;
using JT808.DotNetty.Client.Services;
using JT808.Protocol.Interfaces;

namespace JT808.DotNetty.Client
{
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>();
JT808SendAtomicCounterService jT808SendAtomicCounterService = serviceProvider.GetRequiredService<JT808SendAtomicCounterService>();
JT808ReceiveAtomicCounterService jT808ReceiveAtomicCounterService = serviceProvider.GetRequiredService<JT808ReceiveAtomicCounterService>();
IJT808Config jT808Config = serviceProvider.GetRequiredService<IJT808Config>();
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(jT808Config,jT808SendAtomicCounterService, LoggerFactory));
channel.Pipeline.AddLast("jt808TcpClientConnection", new JT808TcpClientConnectionHandler(this));
channel.Pipeline.AddLast("jt808TcpService", new JT808TcpClientHandler(jT808ReceiveAtomicCounterService,this));
}));
clientChannel = bootstrap.ConnectAsync(IPAddress.Parse(DeviceConfig.TcpHost), DeviceConfig.TcpPort).Result;
}

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);
}
}

public bool IsOpen
{
get
{
if (clientChannel == null) return false;
return clientChannel.Active && clientChannel.Open;
}
}

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);
}
}
}

+ 103
- 0
src/JT808.DotNetty.Client/JT808TcpClientExtensions.cs 查看文件

@@ -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);
}
}
}

+ 62
- 0
src/JT808.DotNetty.Client/JT808TcpClientFactory.cs 查看文件

@@ -0,0 +1,62 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace JT808.DotNetty.Client
{
public interface IJT808TcpClientFactory : IDisposable
{
JT808TcpClient Create(DeviceConfig deviceConfig);

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 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
{
}
}
}

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

+ 49
- 0
src/JT808.DotNetty.Client/Metadata/JT808AtomicCounter.cs 查看文件

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

namespace JT808.DotNetty.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.DotNetty.Client/Metadata/JT808ClientRequest.cs 查看文件

@@ -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;
}
}
}

+ 16
- 0
src/JT808.DotNetty.Client/Metadata/JT808Report.cs 查看文件

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

namespace JT808.DotNetty.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.DotNetty.Client/Services/JT808ReceiveAtomicCounterService.cs 查看文件

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

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

+ 37
- 0
src/JT808.DotNetty.Client/Services/JT808ReportHostedService.cs 查看文件

@@ -0,0 +1,37 @@
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace JT808.DotNetty.Client.Services
{
public class JT808ReportHostedService : IHostedService
{
private readonly JT808ReportService jT808ReportService;
private CancellationTokenSource cts = new CancellationTokenSource();
public JT808ReportHostedService(JT808ReportService jT808ReportService)
{
this.jT808ReportService = jT808ReportService;
}
public Task StartAsync(CancellationToken cancellationToken)
{
Task.Run(() =>
{
while (!cts.IsCancellationRequested)
{
jT808ReportService.Create();
Thread.Sleep(1000);
//Task.Delay(TimeSpan.FromSeconds(1), cts.Token);
}
}, cts.Token);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
cts.Cancel();
return Task.CompletedTask;
}
}
}

+ 42
- 0
src/JT808.DotNetty.Client/Services/JT808ReportService.cs 查看文件

@@ -0,0 +1,42 @@
using JT808.DotNetty.Client.Metadata;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace JT808.DotNetty.Client.Services
{
public class JT808ReportService
{
private readonly JT808ReceiveAtomicCounterService jT808ReceiveAtomicCounterService;
private readonly JT808SendAtomicCounterService jT808SendAtomicCounterService;
private readonly IJT808TcpClientFactory jT808TcpClientFactory;

public List<JT808Report> JT808Reports { get; private set; }

public JT808ReportService(
JT808ReceiveAtomicCounterService jT808ReceiveAtomicCounterService,
JT808SendAtomicCounterService jT808SendAtomicCounterService,
IJT808TcpClientFactory jT808TcpClientFactory)
{
this.jT808ReceiveAtomicCounterService = jT808ReceiveAtomicCounterService;
this.jT808SendAtomicCounterService = jT808SendAtomicCounterService;
this.jT808TcpClientFactory = jT808TcpClientFactory;
JT808Reports = new List<JT808Report>();
}

public void Create()
{
var clients = jT808TcpClientFactory.GetAll();
JT808Reports.Add(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(),
});
}
}
}

+ 35
- 0
src/JT808.DotNetty.Client/Services/JT808SendAtomicCounterService.cs 查看文件

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

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

+ 20
- 0
src/JT808.DotNetty.Core/Codecs/JT808TcpDecoder.cs 查看文件

@@ -0,0 +1,20 @@
using DotNetty.Buffers;
using DotNetty.Codecs;
using System.Collections.Generic;
using JT808.Protocol;
using DotNetty.Transport.Channels;

namespace JT808.DotNetty.Core.Codecs
{
public class JT808TcpDecoder : 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);
}
}
}

+ 67
- 0
src/JT808.DotNetty.Core/Codecs/JT808TcpEncoder.cs 查看文件

@@ -0,0 +1,67 @@
using DotNetty.Buffers;
using DotNetty.Codecs;
using JT808.Protocol;
using DotNetty.Transport.Channels;
using JT808.DotNetty.Core.Interfaces;
using Microsoft.Extensions.Logging;
using JT808.DotNetty.Core.Services;
using JT808.DotNetty.Abstractions;
using JT808.DotNetty.Abstractions.Enums;
using JT808.Protocol.Interfaces;

namespace JT808.DotNetty.Core.Codecs
{
/// <summary>
/// tcp统一下发出口
/// </summary>
public class JT808TcpEncoder : MessageToByteEncoder<IJT808Reply>
{
private readonly ILogger<JT808TcpEncoder> logger;

private readonly JT808TrafficService jT808TrafficService;

private readonly IJT808DownlinkPacket jT808DownlinkPacket;

private readonly JT808Serializer JT808Serializer;

public JT808TcpEncoder(
IJT808Config jT808Config,
ILoggerFactory loggerFactory,
JT808TrafficServiceFactory jT808TrafficServiceFactory,
IJT808DownlinkPacket jT808DownlinkPacket)
{
logger = loggerFactory.CreateLogger<JT808TcpEncoder>();
this.jT808TrafficService = jT808TrafficServiceFactory.Create(JT808TransportProtocolType.tcp);
this.jT808DownlinkPacket = jT808DownlinkPacket;
this.JT808Serializer = jT808Config.GetSerializer();
}

protected override void Encode(IChannelHandlerContext context, IJT808Reply message, IByteBuffer output)
{
if (message.Package != null)
{
try
{
var sendData = JT808Serializer.Serialize(message.Package, message.MinBufferSize);
jT808TrafficService.SendSize(sendData.Length);
jT808DownlinkPacket.ProcessorAsync(sendData, JT808TransportProtocolType.tcp);
output.WriteBytes(Unpooled.WrappedBuffer(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)
{
jT808TrafficService.SendSize(message.HexData.Length);
jT808DownlinkPacket.ProcessorAsync(message.HexData, JT808TransportProtocolType.tcp);
output.WriteBytes(Unpooled.WrappedBuffer(message.HexData));
}
}
}
}

+ 21
- 0
src/JT808.DotNetty.Core/Codecs/JT808UdpDecoder.cs 查看文件

@@ -0,0 +1,21 @@
using DotNetty.Buffers;
using DotNetty.Codecs;
using DotNetty.Transport.Channels;
using System.Collections.Generic;
using DotNetty.Transport.Channels.Sockets;
using JT808.DotNetty.Core.Metadata;

namespace JT808.DotNetty.Core.Codecs
{
public class JT808UdpDecoder : MessageToMessageDecoder<DatagramPacket>
{
protected override void Decode(IChannelHandlerContext context, DatagramPacket message, List<object> output)
{
if (!message.Content.IsReadable()) return;
IByteBuffer byteBuffer = message.Content;
byte[] buffer = new byte[byteBuffer.ReadableBytes];
byteBuffer.ReadBytes(buffer);
output.Add(new JT808UdpPackage(buffer, message.Sender));
}
}
}

+ 31
- 0
src/JT808.DotNetty.Core/Configurations/JT808ClientConfiguration.cs 查看文件

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

namespace JT808.DotNetty.Core.Configurations
{
public class JT808ClientConfiguration
{
public string Host { get; set; }

public int Port { get; set; }

private EndPoint endPoint;

public EndPoint EndPoint
{
get
{
if (endPoint == null)
{
if (IPAddress.TryParse(Host, out IPAddress ip))
{
endPoint = new IPEndPoint(ip, Port);
}
}
return endPoint;
}
}
}
}

+ 47
- 0
src/JT808.DotNetty.Core/Configurations/JT808Configuration.cs 查看文件

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

namespace JT808.DotNetty.Core.Configurations
{
public class JT808Configuration
{
public int TcpPort { get; set; } = 808;

public int UdpPort { get; set; } = 808;

public int QuietPeriodSeconds { get; set; } = 1;

public TimeSpan QuietPeriodTimeSpan => TimeSpan.FromSeconds(QuietPeriodSeconds);

public int ShutdownTimeoutSeconds { get; set; } = 3;

public TimeSpan ShutdownTimeoutTimeSpan => TimeSpan.FromSeconds(ShutdownTimeoutSeconds);

public int SoBacklog { get; set; } = 8192;

public int EventLoopCount { get; set; } = Environment.ProcessorCount;

public int ReaderIdleTimeSeconds { get; set; } = 3600;

public int WriterIdleTimeSeconds { get; set; } = 3600;

public int AllIdleTimeSeconds { get; set; } = 3600;

/// <summary>
/// WebApi服务
/// 默认828端口
/// </summary>
public int WebApiPort { get; set; } = 828;

/// <summary>
/// 转发远程地址 (可选项)知道转发的地址有利于提升性能
/// 按照808的消息,有些请求必须要应答,但是转发可以不需要有应答可以节省部分资源包括:
// 1.消息的序列化
// 2.消息的下发
// 都有一定的性能损耗,那么不需要判断写超时 IdleState.WriterIdle
// 就跟神兽貔貅一样。。。
/// </summary>
public List<string> ForwardingRemoteIPAddress { get; set; }
}
}

+ 29
- 0
src/JT808.DotNetty.Core/Converters/JsonByteArrayHexConverter.cs 查看文件

@@ -0,0 +1,29 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace JT808.DotNetty.Core.Converters
{
class ByteArrayHexConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => objectType == typeof(byte[]);

public override bool CanRead => false;
public override bool CanWrite => true;

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => throw new NotImplementedException();

private readonly string _separator;

public ByteArrayHexConverter(string separator = " ") => _separator = separator;

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var hexString = string.Join(_separator, ((byte[])value).Select(p => p.ToString("X2")));
writer.WriteValue(hexString);
}
}
}

+ 26
- 0
src/JT808.DotNetty.Core/Converters/JsonIPAddressConverter.cs 查看文件

@@ -0,0 +1,26 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;

namespace JT808.DotNetty.Core.Converters
{
public class JsonIPAddressConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(IPAddress));
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(value.ToString());
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return IPAddress.Parse((string)reader.Value);
}
}
}

+ 32
- 0
src/JT808.DotNetty.Core/Converters/JsonIPEndPointConverter.cs 查看文件

@@ -0,0 +1,32 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Net;

namespace JT808.DotNetty.Core.Converters
{
public class JsonIPEndPointConverter: JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(IPEndPoint));
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
IPEndPoint ep = (IPEndPoint)value;
JObject jo = new JObject();
jo.Add("Host", JToken.FromObject(ep.Address, serializer));
jo.Add("Port", ep.Port);
jo.WriteTo(writer);
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
IPAddress address = jo["Host"].ToObject<IPAddress>(serializer);
int port = (int)jo["Port"];
return new IPEndPoint(address, port);
}
}
}

+ 91
- 0
src/JT808.DotNetty.Core/Handlers/JT808MsgIdHttpHandlerBase.cs 查看文件

@@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Text;
using JT808.DotNetty.Abstractions.Dtos;
using JT808.DotNetty.Core.Metadata;
using Newtonsoft.Json;

namespace JT808.DotNetty.Core.Handlers
{
/// <summary>
/// 基于webapi http模式抽象消息处理业务
/// 自定义消息处理业务
/// 注意:
/// 1.ConfigureServices:
/// services.Replace(new ServiceDescriptor(typeof(JT808MsgIdHttpHandlerBase),typeof(JT808MsgIdCustomHttpHandlerImpl),ServiceLifetime.Singleton));
/// 2.解析具体的消息体,具体消息调用具体的JT808Serializer.Deserialize<T>
/// </summary>
public abstract class JT808MsgIdHttpHandlerBase
{
/// <summary>
/// 初始化消息处理业务
/// </summary>
protected JT808MsgIdHttpHandlerBase()
{
HandlerDict = new Dictionary<string, Func<JT808HttpRequest, JT808HttpResponse>>();
}

protected void CreateRoute(string url, Func<JT808HttpRequest, JT808HttpResponse> func)
{
if (!HandlerDict.ContainsKey(url))
{
HandlerDict.Add(url, func);
}
else
{
// 替换
HandlerDict[url] = func;
}
}

public Dictionary<string, Func<JT808HttpRequest, JT808HttpResponse>> HandlerDict { get; }

protected JT808HttpResponse CreateJT808HttpResponse(dynamic dynamicObject)
{
byte[] data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(dynamicObject));
return new JT808HttpResponse()
{
Data = data
};
}

public JT808HttpResponse DefaultHttpResponse()
{
byte[] json = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new JT808DefaultResultDto()));
return new JT808HttpResponse(json);
}

public JT808HttpResponse EmptyHttpResponse()
{
byte[] json = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new JT808ResultDto<string>()
{
Code = JT808ResultCode.Empty,
Message = "内容为空",
Data = "Content Empty"
}));
return new JT808HttpResponse(json);
}

public JT808HttpResponse NotFoundHttpResponse()
{
byte[] json = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new JT808ResultDto<string>()
{
Code = JT808ResultCode.NotFound,
Message = "没有该服务",
Data = "没有该服务"
}));
return new JT808HttpResponse(json);
}

public JT808HttpResponse ErrorHttpResponse(Exception ex)
{
byte[] json = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new JT808ResultDto<string>()
{
Code = JT808ResultCode.Error,
Message = JsonConvert.SerializeObject(ex),
Data = ex.Message
}));
return new JT808HttpResponse(json);
}
}
}

+ 153
- 0
src/JT808.DotNetty.Core/Handlers/JT808MsgIdTcpHandlerBase.cs 查看文件

@@ -0,0 +1,153 @@
using System;
using System.Collections.Generic;
using JT808.DotNetty.Core.Interfaces;
using JT808.DotNetty.Core.Metadata;
using JT808.Protocol.Enums;
using JT808.Protocol.Extensions;
using JT808.Protocol.MessageBody;

namespace JT808.DotNetty.Core.Handlers
{
/// <summary>
/// 基于Tcp模式抽象消息处理业务
/// 自定义消息处理业务
/// 注意:
/// 1.ConfigureServices:
/// services.Replace(new ServiceDescriptor(typeof(JT808MsgIdTcpHandlerBase),typeof(JT808MsgIdCustomTcpHandlerImpl),ServiceLifetime.Singleton));
/// 2.解析具体的消息体,具体消息调用具体的JT808Serializer.Deserialize<T>
/// </summary>
public abstract class JT808MsgIdTcpHandlerBase
{
protected JT808TcpSessionManager sessionManager { get; }
/// <summary>
/// 初始化消息处理业务
/// </summary>
protected JT808MsgIdTcpHandlerBase(JT808TcpSessionManager sessionManager)
{
this.sessionManager = sessionManager;
HandlerDict = new Dictionary<ushort, Func<JT808Request, IJT808Reply>>
{
{JT808MsgId.终端通用应答.ToUInt16Value(), Msg0x0001},
{JT808MsgId.终端鉴权.ToUInt16Value(), Msg0x0102},
{JT808MsgId.终端心跳.ToUInt16Value(), Msg0x0002},
{JT808MsgId.终端注销.ToUInt16Value(), Msg0x0003},
{JT808MsgId.终端注册.ToUInt16Value(), Msg0x0100},
{JT808MsgId.位置信息汇报.ToUInt16Value(),Msg0x0200 },
{JT808MsgId.定位数据批量上传.ToUInt16Value(),Msg0x0704 },
{JT808MsgId.数据上行透传.ToUInt16Value(),Msg0x0900 }
};
}

public Dictionary<ushort, Func<JT808Request, IJT808Reply>> HandlerDict { get; protected set; }
/// <summary>
/// 终端通用应答
/// 平台无需回复
/// 实现自己的业务
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public virtual IJT808Reply Msg0x0001(JT808Request request)
{
return null;
}
/// <summary>
/// 终端心跳
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public virtual IJT808Reply Msg0x0002(JT808Request request)
{
sessionManager.Heartbeat(request.Package.Header.TerminalPhoneNo);
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001()
{
MsgId = request.Package.Header.MsgId,
JT808PlatformResult = JT808PlatformResult.成功,
MsgNum = request.Package.Header.MsgNum
}));
}
/// <summary>
/// 终端注销
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public virtual IJT808Reply Msg0x0003(JT808Request request)
{
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001()
{
MsgId = request.Package.Header.MsgId,
JT808PlatformResult = JT808PlatformResult.成功,
MsgNum = request.Package.Header.MsgNum
}));
}
/// <summary>
/// 终端注册
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public virtual IJT808Reply Msg0x0100(JT808Request request)
{
return new JT808Response(JT808MsgId.终端注册应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8100()
{
Code = "J" + request.Package.Header.TerminalPhoneNo,
JT808TerminalRegisterResult = JT808TerminalRegisterResult.成功,
MsgNum = request.Package.Header.MsgNum
}));
}
/// <summary>
/// 终端鉴权
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public virtual IJT808Reply Msg0x0102(JT808Request request)
{
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001()
{
MsgId = request.Package.Header.MsgId,
JT808PlatformResult = JT808PlatformResult.成功,
MsgNum = request.Package.Header.MsgNum
}));
}
/// <summary>
/// 位置信息汇报
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public virtual IJT808Reply Msg0x0200(JT808Request request)
{
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001()
{
MsgId = request.Package.Header.MsgId,
JT808PlatformResult = JT808PlatformResult.成功,
MsgNum = request.Package.Header.MsgNum
}));
}
/// <summary>
/// 定位数据批量上传
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public virtual IJT808Reply Msg0x0704(JT808Request request)
{
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001()
{
MsgId =request.Package.Header.MsgId,
JT808PlatformResult = JT808PlatformResult.成功,
MsgNum = request.Package.Header.MsgNum
}));
}
/// <summary>
/// 数据上行透传
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public virtual IJT808Reply Msg0x0900(JT808Request request)
{
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001()
{
MsgId =request.Package.Header.MsgId,
JT808PlatformResult = JT808PlatformResult.成功,
MsgNum = request.Package.Header.MsgNum
}));
}
}
}

+ 154
- 0
src/JT808.DotNetty.Core/Handlers/JT808MsgIdUdpHandlerBase.cs 查看文件

@@ -0,0 +1,154 @@
using System;
using System.Collections.Generic;
using JT808.DotNetty.Core.Interfaces;
using JT808.DotNetty.Core.Metadata;
using JT808.Protocol.Enums;
using JT808.Protocol.Extensions;
using JT808.Protocol.MessageBody;

namespace JT808.DotNetty.Core.Handlers
{
/// <summary>
/// 基于Udp模式的抽象消息处理业务
/// 自定义消息处理业务
/// 注意:
/// 1.ConfigureServices:
/// services.Replace(new ServiceDescriptor(typeof(JT808MsgIdUdpHandlerBase),typeof(JT808MsgIdCustomUdpHandlerImpl),ServiceLifetime.Singleton));
/// 2.解析具体的消息体,具体消息调用具体的JT808Serializer.Deserialize<T>
/// </summary>
public abstract class JT808MsgIdUdpHandlerBase
{
protected JT808UdpSessionManager sessionManager { get; }
/// <summary>
/// 初始化消息处理业务
/// </summary>
protected JT808MsgIdUdpHandlerBase(JT808UdpSessionManager sessionManager)
{
this.sessionManager = sessionManager;
HandlerDict = new Dictionary<ushort, Func<JT808Request, IJT808Reply>>
{
{JT808MsgId.终端通用应答.ToUInt16Value(), Msg0x0001},
{JT808MsgId.终端鉴权.ToUInt16Value(), Msg0x0102},
{JT808MsgId.终端心跳.ToUInt16Value(), Msg0x0002},
{JT808MsgId.终端注销.ToUInt16Value(), Msg0x0003},
{JT808MsgId.终端注册.ToUInt16Value(), Msg0x0100},
{JT808MsgId.位置信息汇报.ToUInt16Value(),Msg0x0200 },
{JT808MsgId.定位数据批量上传.ToUInt16Value(),Msg0x0704 },
{JT808MsgId.数据上行透传.ToUInt16Value(),Msg0x0900 }
};
}

public Dictionary<ushort, Func<JT808Request, IJT808Reply>> HandlerDict { get; protected set; }
/// <summary>
/// 终端通用应答
/// 平台无需回复
/// 实现自己的业务
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public virtual IJT808Reply Msg0x0001(JT808Request request)
{
return null;
}
/// <summary>
/// 终端心跳
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public virtual IJT808Reply Msg0x0002(JT808Request request)
{
sessionManager.Heartbeat(request.Package.Header.TerminalPhoneNo);
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001()
{
MsgId = request.Package.Header.MsgId,
JT808PlatformResult = JT808PlatformResult.成功,
MsgNum = request.Package.Header.MsgNum
}));
}
/// <summary>
/// 终端注销
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public virtual IJT808Reply Msg0x0003(JT808Request request)
{
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001()
{
MsgId = request.Package.Header.MsgId,
JT808PlatformResult = JT808PlatformResult.成功,
MsgNum = request.Package.Header.MsgNum
}));
}
/// <summary>
/// 终端注册
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public virtual IJT808Reply Msg0x0100(JT808Request request)
{
return new JT808Response(JT808MsgId.终端注册应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8100()
{
Code = "J" + request.Package.Header.TerminalPhoneNo,
JT808TerminalRegisterResult = JT808TerminalRegisterResult.成功,
MsgNum = request.Package.Header.MsgNum
}));
}
/// <summary>
/// 终端鉴权
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public virtual IJT808Reply Msg0x0102(JT808Request request)
{
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001()
{
MsgId = request.Package.Header.MsgId,
JT808PlatformResult = JT808PlatformResult.成功,
MsgNum = request.Package.Header.MsgNum
}));
}
/// <summary>
/// 位置信息汇报
/// </summary>
/// <param name="reqJT808Package"></param>
/// <param name="ctx"></param>
/// <returns></returns>
public virtual IJT808Reply Msg0x0200(JT808Request request)
{
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001()
{
MsgId = request.Package.Header.MsgId,
JT808PlatformResult = JT808PlatformResult.成功,
MsgNum = request.Package.Header.MsgNum
}));
}
/// <summary>
/// 定位数据批量上传
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public virtual IJT808Reply Msg0x0704(JT808Request request)
{
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001()
{
MsgId =request.Package.Header.MsgId,
JT808PlatformResult = JT808PlatformResult.成功,
MsgNum = request.Package.Header.MsgNum
}));
}
/// <summary>
/// 数据上行透传
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public virtual IJT808Reply Msg0x0900(JT808Request request)
{
return new JT808Response(JT808MsgId.平台通用应答.Create(request.Package.Header.TerminalPhoneNo, new JT808_0x8001()
{
MsgId =request.Package.Header.MsgId,
JT808PlatformResult = JT808PlatformResult.成功,
MsgNum = request.Package.Header.MsgNum
}));
}
}
}

+ 33
- 0
src/JT808.DotNetty.Core/Impls/JT808DatagramPacketImpl.cs 查看文件

@@ -0,0 +1,33 @@
using DotNetty.Buffers;
using DotNetty.Transport.Channels.Sockets;
using JT808.DotNetty.Abstractions;
using JT808.DotNetty.Abstractions.Enums;
using JT808.DotNetty.Core.Interfaces;
using JT808.DotNetty.Core.Services;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;

namespace JT808.DotNetty.Core.Impls
{
class JT808DatagramPacketImpl : IJT808DatagramPacket
{
private readonly JT808TrafficService jT808TrafficService;
private readonly IJT808DownlinkPacket jT808DownlinkPacket;
public JT808DatagramPacketImpl(
JT808TrafficServiceFactory jT808TrafficServiceFactory,
IJT808DownlinkPacket jT808DownlinkPacket)
{
this.jT808DownlinkPacket = jT808DownlinkPacket;
this.jT808TrafficService = jT808TrafficServiceFactory.Create(JT808TransportProtocolType.udp);
}

public DatagramPacket Create(byte[] message, EndPoint recipient)
{
jT808TrafficService.SendSize(message.Length);
jT808DownlinkPacket.ProcessorAsync(message, JT808TransportProtocolType.udp);
return new DatagramPacket(Unpooled.WrappedBuffer(message), recipient);
}
}
}

+ 17
- 0
src/JT808.DotNetty.Core/Impls/JT808DownlinkPacketEmptyImpl.cs 查看文件

@@ -0,0 +1,17 @@
using JT808.DotNetty.Abstractions;
using JT808.DotNetty.Abstractions.Enums;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace JT808.DotNetty.Core.Impls
{
class JT808DownlinkPacketEmptyImpl : IJT808DownlinkPacket
{
public Task ProcessorAsync(byte[] data, JT808TransportProtocolType transportProtocolType)
{
return Task.CompletedTask;
}
}
}

+ 56
- 0
src/JT808.DotNetty.Core/Impls/JT808NettyBuilderDefault.cs 查看文件

@@ -0,0 +1,56 @@
using JT808.DotNetty.Abstractions;
using JT808.DotNetty.Core.Interfaces;
using JT808.Protocol;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT808.DotNetty.Core.Impls
{
public class JT808NettyBuilderDefault : IJT808NettyBuilder
{
public IJT808Builder JT808Builder { get; }

public JT808NettyBuilderDefault(IJT808Builder builder)
{
JT808Builder = builder;
}

public IJT808NettyBuilder Replace<T>() where T : IJT808SourcePackageDispatcher
{
JT808Builder.Services.Replace(new ServiceDescriptor(typeof(IJT808SourcePackageDispatcher), typeof(T), ServiceLifetime.Singleton));
return this;
}

public IJT808Builder Builder()
{
return JT808Builder;
}

public IJT808NettyBuilder ReplaceSourcePackageDispatcher<T>() where T : IJT808SourcePackageDispatcher
{
JT808Builder.Services.Replace(new ServiceDescriptor(typeof(IJT808SourcePackageDispatcher), typeof(T), ServiceLifetime.Singleton));
return this;
}

public IJT808NettyBuilder ReplaceDownlinkPacket<T>() where T : IJT808DownlinkPacket
{
JT808Builder.Services.Replace(new ServiceDescriptor(typeof(IJT808DownlinkPacket), typeof(T), ServiceLifetime.Singleton));
return this;
}

public IJT808NettyBuilder ReplaceUplinkPacket<T>() where T : IJT808UplinkPacket
{
JT808Builder.Services.Replace(new ServiceDescriptor(typeof(IJT808UplinkPacket), typeof(T), ServiceLifetime.Singleton));
return this;
}

public IJT808NettyBuilder ReplaceSessionPublishing<T>() where T : IJT808SessionPublishing
{
JT808Builder.Services.Replace(new ServiceDescriptor(typeof(IJT808SessionPublishing), typeof(T), ServiceLifetime.Singleton));
return this;
}
}
}

+ 13
- 0
src/JT808.DotNetty.Core/Impls/JT808SessionPublishingEmptyImpl.cs 查看文件

@@ -0,0 +1,13 @@
using JT808.DotNetty.Abstractions;
using System.Threading.Tasks;

namespace JT808.DotNetty.Core
{
internal class JT808SessionPublishingEmptyImpl : IJT808SessionPublishing
{
public Task PublishAsync(string topicName, string value)
{
return Task.CompletedTask;
}
}
}

+ 16
- 0
src/JT808.DotNetty.Core/Impls/JT808SourcePackageDispatcherEmptyImpl.cs 查看文件

@@ -0,0 +1,16 @@
using JT808.DotNetty.Abstractions;
using System.Threading.Tasks;

namespace JT808.DotNetty.Core.Impls
{
/// <summary>
/// 原包分发器默认空实现
/// </summary>
public class JT808SourcePackageDispatcherEmptyImpl : IJT808SourcePackageDispatcher
{
public Task SendAsync(byte[] data)
{
return Task.CompletedTask;
}
}
}

+ 17
- 0
src/JT808.DotNetty.Core/Impls/JT808UplinkPacketEmptyImpl.cs 查看文件

@@ -0,0 +1,17 @@
using JT808.DotNetty.Abstractions;
using JT808.DotNetty.Abstractions.Enums;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace JT808.DotNetty.Core.Impls
{
class JT808UplinkPacketEmptyImpl : IJT808UplinkPacket
{
public Task ProcessorAsync(byte[] data, JT808TransportProtocolType transportProtocolType)
{
return Task.CompletedTask;
}
}
}

+ 13
- 0
src/JT808.DotNetty.Core/Interfaces/IJT808DatagramPacket.cs 查看文件

@@ -0,0 +1,13 @@
using DotNetty.Transport.Channels.Sockets;
using System.Net;

namespace JT808.DotNetty.Core.Interfaces
{
/// <summary>
/// 基于udp的创建发送包
/// </summary>
interface IJT808DatagramPacket
{
DatagramPacket Create(byte[] message, EndPoint recipient);
}
}

+ 19
- 0
src/JT808.DotNetty.Core/Interfaces/IJT808NettyBuilder.cs 查看文件

@@ -0,0 +1,19 @@
using JT808.DotNetty.Abstractions;
using JT808.Protocol;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT808.DotNetty.Core.Interfaces
{
public interface IJT808NettyBuilder
{
IJT808Builder JT808Builder { get; }
IJT808NettyBuilder ReplaceSourcePackageDispatcher<T>() where T : IJT808SourcePackageDispatcher;
IJT808NettyBuilder ReplaceDownlinkPacket<T>() where T: IJT808DownlinkPacket;
IJT808NettyBuilder ReplaceUplinkPacket<T>() where T : IJT808UplinkPacket;
IJT808NettyBuilder ReplaceSessionPublishing<T>() where T : IJT808SessionPublishing;
IJT808Builder Builder();
}
}

+ 17
- 0
src/JT808.DotNetty.Core/Interfaces/IJT808Reply.cs 查看文件

@@ -0,0 +1,17 @@
using JT808.Protocol;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT808.DotNetty.Core.Interfaces
{
public interface IJT808Reply
{
JT808Package Package { get; set; }
byte[] HexData { get; set; }
/// <summary>
/// 根据实际情况适当调整包的大小
/// </summary>
int MinBufferSize { get; set; }
}
}

+ 20
- 0
src/JT808.DotNetty.Core/Interfaces/IJT808TcpCustomMsgIdHandler.cs 查看文件

@@ -0,0 +1,20 @@
using JT808.DotNetty.Core.Metadata;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT808.DotNetty.Core.Interfaces
{
public interface IJT808TcpCustomMsgIdHandler
{
IJT808Reply Proccesser(JT808Request request);
}

public class JT808TcpCustomMsgIdHandlerEmpty : IJT808TcpCustomMsgIdHandler
{
public IJT808Reply Proccesser(JT808Request request)
{
return default;
}
}
}

+ 17
- 0
src/JT808.DotNetty.Core/Interfaces/IJT808TcpNettyBuilder.cs 查看文件

@@ -0,0 +1,17 @@
using JT808.DotNetty.Core.Handlers;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT808.DotNetty.Core.Interfaces
{
public interface IJT808TcpNettyBuilder
{
IJT808NettyBuilder Instance { get; }
IJT808NettyBuilder Builder();
IJT808TcpNettyBuilder ReplaceCustomMsgIdHandler<T>() where T : IJT808TcpCustomMsgIdHandler;
IJT808TcpNettyBuilder ReplaceMsgIdHandler<T>() where T : JT808MsgIdTcpHandlerBase;
IJT808TcpNettyBuilder ReplaceSessionService<T>() where T : IJT808TcpSessionService;
IJT808TcpNettyBuilder ReplaceUnificationSendService<T>() where T : IJT808UnificationTcpSendService;
}
}

+ 25
- 0
src/JT808.DotNetty.Core/Interfaces/IJT808TcpSessionService.cs 查看文件

@@ -0,0 +1,25 @@
using JT808.DotNetty.Abstractions.Dtos;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT808.DotNetty.Core.Interfaces
{
/// <summary>
/// JT808 Tcp会话服务
/// </summary>
public interface IJT808TcpSessionService
{
/// <summary>
/// 获取会话集合
/// </summary>
/// <returns></returns>
JT808ResultDto<List<JT808TcpSessionInfoDto>> GetAll();
/// <summary>
/// 通过设备终端号移除对应会话
/// </summary>
/// <param name="terminalPhoneNo"></param>
/// <returns></returns>
JT808ResultDto<bool> RemoveByTerminalPhoneNo(string terminalPhoneNo);
}
}

+ 20
- 0
src/JT808.DotNetty.Core/Interfaces/IJT808UdpCustomMsgIdHandler.cs 查看文件

@@ -0,0 +1,20 @@
using JT808.DotNetty.Core.Metadata;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT808.DotNetty.Core.Interfaces
{
public interface IJT808UdpCustomMsgIdHandler
{
IJT808Reply Proccesser(JT808Request request);
}

public class JT808UdpCustomMsgIdHandlerEmpty : IJT808UdpCustomMsgIdHandler
{
public IJT808Reply Proccesser(JT808Request request)
{
return default;
}
}
}

+ 17
- 0
src/JT808.DotNetty.Core/Interfaces/IJT808UdpNettyBuilder.cs 查看文件

@@ -0,0 +1,17 @@
using JT808.DotNetty.Core.Handlers;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT808.DotNetty.Core.Interfaces
{
public interface IJT808UdpNettyBuilder
{
IJT808NettyBuilder Instance { get; }
IJT808NettyBuilder Builder();
IJT808UdpNettyBuilder ReplaceCustomMsgIdHandler<T>() where T : IJT808UdpCustomMsgIdHandler;
IJT808UdpNettyBuilder ReplaceMsgIdHandler<T>() where T : JT808MsgIdUdpHandlerBase;
IJT808UdpNettyBuilder ReplaceSessionService<T>() where T : IJT808UdpSessionService;
IJT808UdpNettyBuilder ReplaceUnificationSendService<T>() where T : IJT808UnificationUdpSendService;
}
}

+ 25
- 0
src/JT808.DotNetty.Core/Interfaces/IJT808UdpSessionService.cs 查看文件

@@ -0,0 +1,25 @@
using JT808.DotNetty.Abstractions.Dtos;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT808.DotNetty.Core.Interfaces
{
/// <summary>
/// JT808 Udp会话服务
/// </summary>
public interface IJT808UdpSessionService
{
/// <summary>
/// 获取会话集合
/// </summary>
/// <returns></returns>
JT808ResultDto<List<JT808UdpSessionInfoDto>> GetAll();
/// <summary>
/// 通过设备终端号移除对应会话
/// </summary>
/// <param name="terminalPhoneNo"></param>
/// <returns></returns>
JT808ResultDto<bool> RemoveByTerminalPhoneNo(string terminalPhoneNo);
}
}

+ 12
- 0
src/JT808.DotNetty.Core/Interfaces/IJT808UnificationTcpSendService.cs 查看文件

@@ -0,0 +1,12 @@
using JT808.DotNetty.Abstractions.Dtos;

namespace JT808.DotNetty.Core.Interfaces
{
/// <summary>
/// JT808基于tcp的统一下发命令服务
/// </summary>
public interface IJT808UnificationTcpSendService
{
JT808ResultDto<bool> Send(string terminalPhoneNo, byte[] data);
}
}

+ 12
- 0
src/JT808.DotNetty.Core/Interfaces/IJT808UnificationUdpSendService.cs 查看文件

@@ -0,0 +1,12 @@
using JT808.DotNetty.Abstractions.Dtos;

namespace JT808.DotNetty.Core.Interfaces
{
/// <summary>
/// JT808基于udp的统一下发命令服务
/// </summary>
public interface IJT808UnificationUdpSendService
{
JT808ResultDto<bool> Send(string terminalPhoneNo, byte[] data);
}
}

+ 14
- 0
src/JT808.DotNetty.Core/Interfaces/IJT808WebApiNettyBuilder.cs 查看文件

@@ -0,0 +1,14 @@
using JT808.DotNetty.Core.Handlers;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT808.DotNetty.Core.Interfaces
{
public interface IJT808WebApiNettyBuilder
{
IJT808NettyBuilder Instance { get; }
IJT808NettyBuilder Builder();
IJT808WebApiNettyBuilder ReplaceMsgIdHandler<T>() where T : JT808MsgIdHttpHandlerBase;
}
}

+ 29
- 0
src/JT808.DotNetty.Core/JT808.DotNetty.Core.csproj 查看文件

@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\SharedProperties.props" />
<PropertyGroup>
<PackageId>JT808.DotNetty.Core</PackageId>
<Product>JT808.DotNetty.Core</Product>
<Description>基于DotNetty实现的JT808DotNetty的核心库</Description>
<PackageReleaseNotes>基于DotNetty实现的JT808DotNetty的核心库</PackageReleaseNotes>
</PropertyGroup>

<ItemGroup>
<Compile Remove="Jobs\JT808UdpMaintainSessionJob.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="DotNetty.Handlers" Version="0.6.0" />
<PackageReference Include="DotNetty.Transport.Libuv" Version="0.6.0" />
<PackageReference Include="DotNetty.Codecs" Version="0.6.0" />
<PackageReference Include="JT808" Version="2.1.2" />
<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.2" />
<PackageReference Include="Microsoft.Extensions.Options" Version="2.2.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\JT808.DotNetty.Abstractions\JT808.DotNetty.Abstractions.csproj" />
</ItemGroup>

</Project>

+ 74
- 0
src/JT808.DotNetty.Core/JT808BackgroundService.cs 查看文件

@@ -0,0 +1,74 @@
using Microsoft.Extensions.Hosting;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace JT808.DotNetty.Core
{
/// <summary>
///
/// <see cref="https://blogs.msdn.microsoft.com/cesardelatorre/2017/11/18/implementing-background-tasks-in-microservices-with-ihostedservice-and-the-backgroundservice-class-net-core-2-x/"/>
/// </summary>
public abstract class JT808BackgroundService : IHostedService, IDisposable
{
/// <summary>
/// 默认次日过期
/// </summary>
public virtual TimeSpan DelayTimeSpan
{
get
{
DateTime current = DateTime.Now;
DateTime tmp = current.Date.AddDays(1).AddSeconds(-1);
return tmp.Subtract(current);
}
set { }
}

private Task _executingTask;

public abstract string ServiceName { get; }

private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource();

protected abstract Task ExecuteAsync(CancellationToken stoppingToken);

public void Dispose()
{
_stoppingCts.Cancel();
}

public virtual Task StartAsync(CancellationToken cancellationToken)
{
// Store the task we're executing
_executingTask = ExecuteAsync(_stoppingCts.Token);
// If the task is completed then return it,
// this will bubble cancellation and failure to the caller
if (_executingTask.IsCompleted)
{
return _executingTask;
}
// Otherwise it's running
return Task.CompletedTask;
}

public virtual async Task StopAsync(CancellationToken cancellationToken)
{
// Stop called without start
if (_executingTask == null)
{
return;
}
try
{
// Signal cancellation to the executing method
_stoppingCts.Cancel();
}
finally
{
// Wait until the task completes or the stop token triggers
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite,cancellationToken));
}
}
}
}

+ 96
- 0
src/JT808.DotNetty.Core/JT808CoreDotnettyExtensions.cs 查看文件

@@ -0,0 +1,96 @@
using JT808.DotNetty.Abstractions;
using JT808.DotNetty.Core.Configurations;
using JT808.DotNetty.Core.Converters;
using JT808.DotNetty.Core.Impls;
using JT808.DotNetty.Core.Interfaces;
using JT808.DotNetty.Core.Services;
using JT808.DotNetty.Internal;
using JT808.Protocol;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("JT808.DotNetty.Core.Test")]
[assembly: InternalsVisibleTo("JT808.DotNetty.Tcp.Test")]
[assembly: InternalsVisibleTo("JT808.DotNetty.Udp.Test")]
[assembly: InternalsVisibleTo("JT808.DotNetty.WebApi.Test")]
[assembly: InternalsVisibleTo("JT808.DotNetty.Tcp")]
[assembly: InternalsVisibleTo("JT808.DotNetty.Udp")]
[assembly: InternalsVisibleTo("JT808.DotNetty.WebApi")]
namespace JT808.DotNetty.Core
{
public static class JT808CoreDotnettyExtensions
{
static JT808CoreDotnettyExtensions()
{
JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
Newtonsoft.Json.JsonSerializerSettings settings = new Newtonsoft.Json.JsonSerializerSettings();
//日期类型默认格式化处理
settings.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat;
settings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
//空值处理
settings.NullValueHandling = NullValueHandling.Ignore;
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
settings.Converters.Add(new JsonIPAddressConverter());
settings.Converters.Add(new JsonIPEndPointConverter());
settings.Converters.Add(new ByteArrayHexConverter());
return settings;
});
}

public static IJT808NettyBuilder AddJT808NettyCore(this IJT808Builder jt808Builder, IConfiguration configuration, Newtonsoft.Json.JsonSerializerSettings settings=null)
{
if (settings != null)
{
JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
settings.Converters.Add(new JsonIPAddressConverter());
settings.Converters.Add(new JsonIPEndPointConverter());
settings.Converters.Add(new ByteArrayHexConverter());
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
return settings;
});
}
IJT808NettyBuilder nettyBuilder = new JT808NettyBuilderDefault(jt808Builder);
nettyBuilder.JT808Builder.Services.Configure<JT808Configuration>(configuration.GetSection("JT808Configuration"));
nettyBuilder.JT808Builder.Services.TryAddSingleton<IJT808SessionPublishing, JT808SessionPublishingEmptyImpl>();
nettyBuilder.JT808Builder.Services.TryAddSingleton<IJT808DownlinkPacket, JT808DownlinkPacketEmptyImpl>();
nettyBuilder.JT808Builder.Services.TryAddSingleton<IJT808UplinkPacket, JT808UplinkPacketEmptyImpl>();
nettyBuilder.JT808Builder.Services.TryAddSingleton<IJT808SourcePackageDispatcher, JT808SourcePackageDispatcherEmptyImpl>();
nettyBuilder.JT808Builder.Services.TryAddSingleton<JT808AtomicCounterServiceFactory>();
nettyBuilder.JT808Builder.Services.TryAddSingleton<JT808TrafficServiceFactory>();
nettyBuilder.JT808Builder.Services.TryAddSingleton<JT808SimpleSystemCollectService>();
return nettyBuilder;
}

public static IJT808NettyBuilder AddJT808NettyCore(this IJT808Builder jt808Builder, Action<JT808Configuration> jt808Options, Newtonsoft.Json.JsonSerializerSettings settings = null)
{
if (settings != null)
{
JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
settings.Converters.Add(new JsonIPAddressConverter());
settings.Converters.Add(new JsonIPEndPointConverter());
settings.Converters.Add(new ByteArrayHexConverter());
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
return settings;
});
}
IJT808NettyBuilder nettyBuilder = new JT808NettyBuilderDefault(jt808Builder);
nettyBuilder.JT808Builder.Services.Configure(jt808Options);
nettyBuilder.JT808Builder.Services.TryAddSingleton<IJT808SessionPublishing, JT808SessionPublishingEmptyImpl>();
nettyBuilder.JT808Builder.Services.TryAddSingleton<IJT808DownlinkPacket, JT808DownlinkPacketEmptyImpl>();
nettyBuilder.JT808Builder.Services.TryAddSingleton<IJT808UplinkPacket, JT808UplinkPacketEmptyImpl>();
nettyBuilder.JT808Builder.Services.TryAddSingleton<IJT808SourcePackageDispatcher, JT808SourcePackageDispatcherEmptyImpl>();
nettyBuilder.JT808Builder.Services.TryAddSingleton<JT808AtomicCounterServiceFactory>();
nettyBuilder.JT808Builder.Services.TryAddSingleton<JT808TrafficServiceFactory>();
nettyBuilder.JT808Builder.Services.TryAddSingleton<JT808SimpleSystemCollectService>();
return nettyBuilder;
}
}
}

+ 50
- 0
src/JT808.DotNetty.Core/JT808SimpleTcpClient.cs 查看文件

@@ -0,0 +1,50 @@
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace JT808.DotNetty.Core
{
internal class JT808SimpleTcpClient
{
private TcpClient tcpClient;

public JT808SimpleTcpClient(IPEndPoint remoteAddress)
{
tcpClient = new TcpClient();
tcpClient.Connect(remoteAddress);
Task.Run(()=> {
while (true)
{
try
{
byte[] buffer = new byte[100];
tcpClient.GetStream().Read(buffer, 0, 100);
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " " + string.Join(" ", buffer));
}
catch
{

}
Thread.Sleep(1000);
}
});
}

public void WriteAsync(byte[] data)
{
tcpClient.GetStream().WriteAsync(data, 0, data.Length);
}

public void Down()
{
tcpClient.Close();
}
}
}

+ 48
- 0
src/JT808.DotNetty.Core/JT808SimpleUdpClient.cs 查看文件

@@ -0,0 +1,48 @@
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace JT808.DotNetty.Core
{
internal class JT808SimpleUdpClient
{
private UdpClient udpClient;

public JT808SimpleUdpClient(IPEndPoint remoteAddress)
{
udpClient = new UdpClient();
udpClient.Connect(remoteAddress);
Task.Run(() =>
{
while (true)
{
try
{
string tmp = string.Join(" ", udpClient.Receive(ref remoteAddress));
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " " + tmp);
Thread.Sleep(1000);
}
catch
{


}
Thread.Sleep(1000);
}
});
}

public void WriteAsync(byte[] data)
{
udpClient.SendAsync(data, data.Length);
}

public void Down()
{
udpClient.Close();
}
}
}

+ 38
- 0
src/JT808.DotNetty.Core/Jobs/JT808TcpAtomicCouterResetDailyJob.cs 查看文件

@@ -0,0 +1,38 @@
using JT808.DotNetty.Abstractions.Enums;
using JT808.DotNetty.Core.Services;
using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;

namespace JT808.DotNetty.Core.Jobs
{
internal class JT808TcpAtomicCouterResetDailyJob : JT808BackgroundService
{
private readonly ILogger<JT808TcpAtomicCouterResetDailyJob> _logger;

private readonly JT808AtomicCounterService _jT808AtomicCounterService;

public JT808TcpAtomicCouterResetDailyJob(
JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory,
ILoggerFactory loggerFactory)
{
_jT808AtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.tcp);
_logger =loggerFactory.CreateLogger<JT808TcpAtomicCouterResetDailyJob>();
}

public override string ServiceName => nameof(JT808TcpAtomicCouterResetDailyJob);

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation($"{ServiceName} is starting.");
stoppingToken.Register(() => _logger.LogInformation($"{ServiceName} background task is stopping."));
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation($"{ServiceName} task doing background work.");
_jT808AtomicCounterService.Reset();
await Task.Delay(DelayTimeSpan, stoppingToken);
}
_logger.LogInformation($"{ServiceName} background task is stopping.");
}
}
}

+ 38
- 0
src/JT808.DotNetty.Core/Jobs/JT808TcpTrafficResetDailyJob.cs 查看文件

@@ -0,0 +1,38 @@
using JT808.DotNetty.Abstractions.Enums;
using JT808.DotNetty.Core.Services;
using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;

namespace JT808.DotNetty.Core.Jobs
{
internal class JT808TcpTrafficResetDailyJob : JT808BackgroundService
{
private readonly ILogger<JT808TcpTrafficResetDailyJob> _logger;

private readonly JT808TrafficService _jT808TrafficService;

public JT808TcpTrafficResetDailyJob(
JT808TrafficServiceFactory jT808TrafficServiceFactory,
ILoggerFactory loggerFactory)
{
_jT808TrafficService = jT808TrafficServiceFactory.Create(JT808TransportProtocolType.tcp);
_logger =loggerFactory.CreateLogger<JT808TcpTrafficResetDailyJob>();
}

public override string ServiceName => nameof(JT808TcpTrafficResetDailyJob);

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation($"{ServiceName} is starting.");
stoppingToken.Register(() => _logger.LogInformation($"{ServiceName} background task is stopping."));
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation($"{ServiceName} task doing background work.");
_jT808TrafficService.ResetSize();
await Task.Delay(DelayTimeSpan, stoppingToken);
}
_logger.LogInformation($"{ServiceName} background task is stopping.");
}
}
}

部分文件因为文件数量过多而无法显示

正在加载...
取消
保存