@@ -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 |
@@ -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. |
@@ -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) | |||
[](https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE) | |||
## 新网关的优势: | |||
1. 跨平台 | |||
2. 借助 .NET Core模块化的思想 | |||
3. 单机同时一万辆车在线不是梦(真有一万辆车那都很吃香了<( ̄3 ̄)> <( ̄3 ̄)> <( ̄3 ̄)> ) | |||
4. 简单易上手 | |||
## 设计模型 | |||
 | |||
## 基于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 |  |  | | |||
| Install-Package JT808.DotNetty.Abstractions |  |  | | |||
| Install-Package JT808.DotNetty.Tcp |  |  | | |||
| Install-Package JT808.DotNetty.Udp |  |  | | |||
| Install-Package JT808.DotNetty.WebApi |  |  | | |||
| Install-Package JT808.DotNetty.WebApiClientTool |  |  | | |||
## 举个栗子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(); | |||
} | |||
``` | |||
如图所示: | |||
 | |||
## 举个栗子2 | |||
1.拉取JT808子模块 | |||
2.打开项目进行还原编译生成 | |||
3.进入JT808.DotNetty.SimpleServer项目下的Debug目录运行服务端 | |||
4.进入JT808.DotNetty.SimpleClient项目下的Debug目录运行客户端 | |||
如图所示: | |||
 |
@@ -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" | |||
} | |||
} | |||
``` |
@@ -0,0 +1,16 @@ | |||
## 压力测试 | |||
[感谢泥水佬提供的压力测试工具](https://www.cnblogs.com/smark/p/4496660.html?utm_source=tuicool) | |||
| 操作系统 | 配置 | 使用 | | |||
|:-------:|:-------:|:-------:| | |||
| win server 2016 | 4c8g | 压力测试客户端 | | |||
| centos7 | 4c8g | JT808服务端 | | |||
 | |||
 | |||
 | |||
 |
@@ -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> |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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> |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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 |
@@ -0,0 +1,12 @@ | |||
namespace JT808.DotNetty.Abstractions.Dtos | |||
{ | |||
/// <summary> | |||
/// 包计数器服务 | |||
/// </summary> | |||
public class JT808AtomicCounterDto | |||
{ | |||
public long MsgSuccessCount { get; set; } | |||
public long MsgFailCount { get; set; } | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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 { } | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; } | |||
} | |||
} |
@@ -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; } | |||
} | |||
} |
@@ -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; } | |||
} | |||
} |
@@ -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; } | |||
} | |||
} |
@@ -0,0 +1,11 @@ | |||
namespace JT808.DotNetty.Abstractions.Dtos | |||
{ | |||
/// <summary> | |||
/// 统一下发请求参数 | |||
/// </summary> | |||
public class JT808UnificationSendRequestDto | |||
{ | |||
public string TerminalPhoneNo { get; set; } | |||
public byte[] Data { get; set; } | |||
} | |||
} |
@@ -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 | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
using System.Threading.Tasks; | |||
namespace JT808.DotNetty.Abstractions | |||
{ | |||
/// <summary> | |||
/// 会话通知(在线/离线) | |||
/// </summary> | |||
public interface IJT808SessionPublishing | |||
{ | |||
Task PublishAsync(string topicName, string value); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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> |
@@ -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"; | |||
} | |||
} | |||
} |
@@ -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> |
@@ -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> |
@@ -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; | |||
} | |||
} |
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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 | |||
} | |||
} |
@@ -0,0 +1,20 @@ | |||
using DotNetty.Buffers; | |||
using DotNetty.Codecs; | |||
using System.Collections.Generic; | |||
using JT808.Protocol; | |||
using DotNetty.Transport.Channels; | |||
namespace JT808.DotNetty.Client.Codecs | |||
{ | |||
public class JT808ClientTcpDecoder : ByteToMessageDecoder | |||
{ | |||
protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List<object> output) | |||
{ | |||
byte[] buffer = new byte[input.Capacity + 2]; | |||
input.ReadBytes(buffer, 1, input.Capacity); | |||
buffer[0] = JT808Package.BeginFlag; | |||
buffer[input.Capacity + 1] = JT808Package.EndFlag; | |||
output.Add(buffer); | |||
} | |||
} | |||
} |
@@ -0,0 +1,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(); | |||
} | |||
} | |||
} | |||
} |
@@ -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; } | |||
} | |||
} |
@@ -0,0 +1,95 @@ | |||
using DotNetty.Handlers.Timeout; | |||
using DotNetty.Transport.Channels; | |||
using JT808.Protocol.MessageBody; | |||
using Microsoft.Extensions.Logging; | |||
using System; | |||
using System.Threading.Tasks; | |||
namespace JT808.DotNetty.Client.Handlers | |||
{ | |||
/// <summary> | |||
/// JT808客户端连接通道处理程序 | |||
/// </summary> | |||
public class JT808TcpClientConnectionHandler : ChannelHandlerAdapter | |||
{ | |||
private readonly ILogger<JT808TcpClientConnectionHandler> logger; | |||
private readonly JT808TcpClient jT808TcpClient; | |||
public JT808TcpClientConnectionHandler( | |||
JT808TcpClient jT808TcpClient) | |||
{ | |||
logger = jT808TcpClient.LoggerFactory.CreateLogger<JT808TcpClientConnectionHandler>(); | |||
this.jT808TcpClient = jT808TcpClient; | |||
} | |||
/// <summary> | |||
/// 通道激活 | |||
/// </summary> | |||
/// <param name="context"></param> | |||
public override void ChannelActive(IChannelHandlerContext context) | |||
{ | |||
string channelId = context.Channel.Id.AsShortText(); | |||
if (logger.IsEnabled(LogLevel.Debug)) | |||
logger.LogDebug($"<<<{ channelId } Successful client connection to server."); | |||
base.ChannelActive(context); | |||
} | |||
/// <summary> | |||
/// 设备主动断开 | |||
/// </summary> | |||
/// <param name="context"></param> | |||
public override void ChannelInactive(IChannelHandlerContext context) | |||
{ | |||
string channelId = context.Channel.Id.AsShortText(); | |||
if (logger.IsEnabled(LogLevel.Debug)) | |||
logger.LogDebug($">>>{ channelId } The client disconnects from the server."); | |||
base.ChannelInactive(context); | |||
} | |||
/// <summary> | |||
/// 服务器主动断开 | |||
/// </summary> | |||
/// <param name="context"></param> | |||
/// <returns></returns> | |||
public override Task CloseAsync(IChannelHandlerContext context) | |||
{ | |||
string channelId = context.Channel.Id.AsShortText(); | |||
if (logger.IsEnabled(LogLevel.Debug)) | |||
logger.LogDebug($"<<<{ channelId } The server disconnects from the client."); | |||
return base.CloseAsync(context); | |||
} | |||
public override void ChannelReadComplete(IChannelHandlerContext context)=> context.Flush(); | |||
/// <summary> | |||
/// 超时策略 | |||
/// </summary> | |||
/// <param name="context"></param> | |||
/// <param name="evt"></param> | |||
public override void UserEventTriggered(IChannelHandlerContext context, object evt) | |||
{ | |||
IdleStateEvent idleStateEvent = evt as IdleStateEvent; | |||
if (idleStateEvent != null) | |||
{ | |||
if(idleStateEvent.State== IdleState.WriterIdle) | |||
{ | |||
string channelId = context.Channel.Id.AsShortText(); | |||
logger.LogInformation($"{idleStateEvent.State.ToString()}>>>{channelId}"); | |||
jT808TcpClient.Send(new JT808_0x0002()); | |||
} | |||
} | |||
base.UserEventTriggered(context, evt); | |||
} | |||
public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) | |||
{ | |||
string channelId = context.Channel.Id.AsShortText(); | |||
logger.LogError(exception,$"{channelId} {exception.Message}" ); | |||
context.CloseAsync(); | |||
} | |||
} | |||
} | |||
@@ -0,0 +1,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(); | |||
} | |||
} | |||
} |
@@ -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> |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -0,0 +1,103 @@ | |||
using JT808.DotNetty.Client.Metadata; | |||
using JT808.Protocol; | |||
using JT808.Protocol.MessageBody; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
using JT808.Protocol.Enums; | |||
using JT808.Protocol.Extensions; | |||
namespace JT808.DotNetty.Client | |||
{ | |||
public static class JT808TcpClientExtensions | |||
{ | |||
public static void Send(this JT808TcpClient client, JT808Header header, JT808Bodies bodies, int minBufferSize = 1024) | |||
{ | |||
JT808Package package = new JT808Package(); | |||
package.Header = header; | |||
package.Bodies = bodies; | |||
package.Header.TerminalPhoneNo = client.DeviceConfig.TerminalPhoneNo; | |||
package.Header.MsgNum = client.DeviceConfig.MsgSNDistributed.Increment(); | |||
JT808ClientRequest request = new JT808ClientRequest(package, minBufferSize); | |||
client.Send(request); | |||
} | |||
/// <summary> | |||
/// 终端通用应答 | |||
/// </summary> | |||
/// <param name="client"></param> | |||
/// <param name="bodies"></param> | |||
/// <param name="minBufferSize"></param> | |||
public static void Send(this JT808TcpClient client, JT808_0x0001 bodies, int minBufferSize = 100) | |||
{ | |||
JT808Header header = new JT808Header(); | |||
header.MsgId = JT808MsgId.终端通用应答.ToUInt16Value(); | |||
client.Send(header, bodies, minBufferSize); | |||
} | |||
/// <summary> | |||
/// 终端心跳 | |||
/// </summary> | |||
/// <param name="client"></param> | |||
/// <param name="bodies"></param> | |||
/// <param name="minBufferSize"></param> | |||
public static void Send(this JT808TcpClient client, JT808_0x0002 bodies, int minBufferSize = 100) | |||
{ | |||
JT808Header header = new JT808Header(); | |||
header.MsgId = JT808MsgId.终端心跳.ToUInt16Value(); | |||
client.Send(header, bodies, minBufferSize); | |||
} | |||
/// <summary> | |||
/// 终端注销 | |||
/// </summary> | |||
/// <param name="client"></param> | |||
/// <param name="bodies"></param> | |||
/// <param name="minBufferSize"></param> | |||
public static void Send(this JT808TcpClient client, JT808_0x0003 bodies, int minBufferSize = 100) | |||
{ | |||
JT808Header header = new JT808Header(); | |||
header.MsgId = JT808MsgId.终端注销.ToUInt16Value(); | |||
client.Send(header, bodies, minBufferSize); | |||
} | |||
/// <summary> | |||
/// 终端鉴权 | |||
/// </summary> | |||
/// <param name="client"></param> | |||
/// <param name="bodies"></param> | |||
/// <param name="minBufferSize"></param> | |||
public static void Send(this JT808TcpClient client, JT808_0x0102 bodies, int minBufferSize = 100) | |||
{ | |||
JT808Header header = new JT808Header(); | |||
header.MsgId = JT808MsgId.终端鉴权.ToUInt16Value(); | |||
client.Send(header, bodies, minBufferSize); | |||
} | |||
/// <summary> | |||
/// 终端注册 | |||
/// </summary> | |||
/// <param name="client"></param> | |||
/// <param name="bodies"></param> | |||
/// <param name="minBufferSize"></param> | |||
public static void Send(this JT808TcpClient client, JT808_0x0100 bodies, int minBufferSize = 100) | |||
{ | |||
JT808Header header = new JT808Header(); | |||
header.MsgId = JT808MsgId.终端注册.ToUInt16Value(); | |||
client.Send(header, bodies, minBufferSize); | |||
} | |||
/// <summary> | |||
/// 位置信息汇报 | |||
/// </summary> | |||
/// <param name="client"></param> | |||
/// <param name="bodies"></param> | |||
/// <param name="minBufferSize"></param> | |||
public static void Send(this JT808TcpClient client, JT808_0x0200 bodies, int minBufferSize = 200) | |||
{ | |||
JT808Header header = new JT808Header(); | |||
header.MsgId = JT808MsgId.位置信息汇报.ToUInt16Value(); | |||
client.Send(header, bodies, minBufferSize); | |||
} | |||
} | |||
} |
@@ -0,0 +1,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(); | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; } | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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(), | |||
}); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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)); | |||
} | |||
} | |||
} | |||
} |
@@ -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)); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} | |||
} |
@@ -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; } | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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 | |||
})); | |||
} | |||
} | |||
} |
@@ -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 | |||
})); | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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; } | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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> |
@@ -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)); | |||
} | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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."); | |||
} | |||
} | |||
} |
@@ -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."); | |||
} | |||
} | |||
} |