diff --git a/README.md b/README.md index fb721d4..19ed6a6 100644 --- a/README.md +++ b/README.md @@ -2,24 +2,346 @@ 基于DotNetty封装的JT808DotNetty专注消息业务处理 +[了解JT808协议进这边](https://github.com/SmallChi/JT808) + +[了解JT809协议进这边](https://github.com/SmallChi/JT809) + + [玩一玩压力测试](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/README.md) + +[![MIT Licence](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/SmallChi/JT808DotNetty/blob/master/LICENSE) + +## 新网关的优势: + +1. 跨平台 +2. 借助 .NET Core模块化的思想 +3. 单机同时一万辆车在线不是梦(真有一万辆车那都很吃香了<( ̄3 ̄)> <( ̄3 ̄)> <( ̄3 ̄)> ) +4. 简单易上手 + +## 设计模型 + +![design_model](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/design_model.png) + +## NuGet安装 + +| Package Name | Version | Downloads | +| --------------------- | -------------------------------------------------- | --------------------------------------------------- | +| Install-Package JT808DotNetty | ![JT808DotNetty](https://img.shields.io/nuget/v/JT808DotNetty.svg) | ![JT808DotNetty](https://img.shields.io/nuget/dt/JT808DotNetty.svg) | + ## 集成功能实现 ### 1.集成原包分发器 | 功能 | 说明 | 使用场景 | |:-------:|:-------:|:-------:| -| ISourcePackageDispatcher | 原包分发器(支持热更新) | 需要将源数据转给其他平台 | +| ISourcePackageDispatcher | 原包分发器(支持热更新、断线重连) | 需要将原数据转给其他平台 | -### 2.集成WebApi服务器(默认端口828) +### 2.集成WebApi服务器 -#### 2.1.统一下发设备消息服务 IJT808UnificationSendService +#### [2.1.统一下发设备消息服务 IJT808UnificationSendService](#send) -#### 2.2.管理会话服务 IJT808SessionService +#### [2.2.管理会话服务 IJT808SessionService](#session) -#### 2.3.消息包计数服务 JT808AtomicCounterService +#### [2.3.消息包计数服务 JT808AtomicCounterService 接口尚未实现](#counter) ### 3.集成业务消息处理程序 | 功能 | 说明 | 使用场景 | |:-------:|:-------:|:-------:| -| JT808MsgIdHandlerBase | 业务消息处理程序 | 需要自定义实现业务消息处理程序 | \ No newline at end of file +| JT808MsgIdHandlerBase | 业务消息处理程序 | 需要自定义实现业务消息处理程序 | + +### 举个栗子1 + +#### 1.实现业务消息处理程序JT808MsgIdHandlerBase + +```business Impl +using JT808.DotNetty; +public class JT808MsgIdCustomHandler : JT808MsgIdHandlerBase +{ + private readonly ILogger logger; + + public JT808MsgIdCustomHandler(ILoggerFactory loggerFactory, + JT808SessionManager sessionManager) : base(sessionManager) + { + logger = loggerFactory.CreateLogger(); + } + + public override JT808Response Msg0x0102(JT808Request request) + { + logger.LogDebug("Msg0x0102"); + return base.Msg0x0102(request); + } +} + +``` +#### 2.自定义业务消息处理程序替换默认实现 + +``` +services.Replace(new ServiceDescriptor(typeof(JT808MsgIdHandlerBase), typeof(JT808MsgIdCustomHandler), ServiceLifetime.Singleton)); +``` +#### 3.使用JT808 Host + +``` host + UseJT808Host() +``` + +#### 4.完整示例 +``` demo +// 默认网关端口:808 +// 默认webapi端口:828 +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.Error); + }) + .ConfigureServices((hostContext, services) => + { + services.AddSingleton(); + services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); + services.Replace(new ServiceDescriptor(typeof(JT808MsgIdHandlerBase), typeof(JT808MsgIdCustomHandler), ServiceLifetime.Singleton)); + }) + .UseJT808Host(); + await serverHostBuilder.RunConsoleAsync(); +} +``` + +## 提供WebApi接口服务(默认端口828) + +基地址:http://localhost:828/jt808api/ +数据格式:只支持Json格式 + +#### 统一对象返回 JT808ResultDto\ + +|属性|数据类型|参数说明| +|:------:|:------:|:------| +| Message| string| 消息描述| +| Code| int| 状态码| +| Data| T(泛型)| 数据| + +返回Code[状态码]说明: +|状态码|说明| +|:------:|:------:| +| 200 | 返回成功 | +| 201 | 内容为空 | +| 404 | 没有该服务 | +| 500 | 服务内部错误 | + +#### 统一下发设备消息接口 + +请求地址:UnificationSend +请求方式:POST +请求参数: +|属性|数据类型|参数说明| +|:------:|:------:|:------| +| TerminalPhoneNo| string| 设备终端号| +| Data| byte[]| JT808 byte[]数组| +返回数据: +|属性|数据类型|参数说明| +|:------:|:------:|:------| +| Data| bool| 是否成功| +返回结果: +``` result1 +{ + "Message":"", + "Code":200, + "Data":true +} +``` +#### 会话服务接口 + +##### 统一会话信息对象返回 JT808SessionInfoDto + +|属性|数据类型|参数说明| +|:------:|:------:|:------| +| ChannelId| string| 通道Id| +| LastActiveTime| DateTime| 最后上线时间| +| StartTime| DateTime| 上线时间| +| TerminalPhoneNo|string| 终端手机号| + +##### 1.获取实际连接数(存在其他平台转发过来的数据,这时候通道Id和设备属于一对多的关系) + +请求地址:Session/GetRealLinkCount +请求方式:GET +返回数据: +|属性|数据类型|参数说明| +|:------:|:------:|:------| +| Data| int| 实际连接数| +返回结果: +``` result1 +{ + "Message":"", + "Code":200, + "Data":10 +} +``` +##### 2.获取设备相关连的连接数 + +请求地址:Session/GetRelevanceLinkCount +请求方式:GET +返回数据: +|属性|数据类型|参数说明| +|:------:|:------:|:------| +| Data| int | 设备相关连的连接数 | +返回结果: +``` result2 +{ + "Message":"", + "Code":200, + "Data":10 +} +``` +##### 3.获取实际会话集合 + +请求地址:Session/GetRealAll +请求方式:GET +返回数据: +|属性|数据类型|参数说明| +|:------:|:------:|:------| +| Data| List\ | 实际会话信息集合 | +返回结果: +``` result3 +{ + "Message":"", + "Code":200, + "Data":[ + { + "ChannelId":"eadad23", + "LastActiveTime":"2018-11-27 20:00:00", + "StartTime":"2018-11-25 20:00:00", + "TerminalPhoneNo":"123456789012" + },{ + "ChannelId":"eadad23", + "LastActiveTime":"2018-11-27 20:00:00", + "StartTime":"2018-11-25 20:00:00", + "TerminalPhoneNo":"123456789013" + } + ] +} +``` +##### 4.获取设备相关联会话集合 + +请求地址:Session/GetRelevanceAll +请求方式:GET +返回数据: +|属性|数据类型|参数说明| +|:------:|:------:|:------| +| Data| List\ | 设备相关联会话信息集合 | +返回结果: +``` result4 +{ + "Message":"", + "Code":200, + "Data":[ + { + "ChannelId":"eadad23", + "LastActiveTime":"2018-11-27 20:00:00", + "StartTime":"2018-11-25 20:00:00", + "TerminalPhoneNo":"123456789012" + }, { + "ChannelId":"eadad24", + "LastActiveTime":"2018-11-26 20:00:00", + "StartTime":"2018-11-22 20:00:00", + "TerminalPhoneNo":"123456789013" + } + ] +} +``` + +##### 5.通过通道Id移除对应会话 + +请求地址:Session/RemoveByChannelId +请求方式:POST +请求参数: +|属性|数据类型|参数说明| +|:------:|:------:|:------| +| channelId| string| 通道Id| +返回数据: +|属性|数据类型|参数说明| +|:------:|:------:|:------| +| Data| bool | 是否成功 | +返回结果: +``` result5 +{ + "Message":"", + "Code":200, + "Data":true +} +``` +##### 6.通过设备终端号移除对应会话 + +请求地址:Session/RemoveByTerminalPhoneNo +请求方式:POST +请求参数: +|属性|数据类型|参数说明| +|:------:|:------:|:------| +| terminalPhoneNo| string| 设备终端号| +返回数据: +|属性|数据类型|参数说明| +|:------:|:------:|:------| +| Data| bool | 是否成功 | +返回结果: +``` result6 +{ + "Message":"", + "Code":200, + "Data":true +} +``` +##### 7.通过通道Id获取会话信息 + +请求地址:Session/GetByChannelId +请求方式:POST +请求参数: +|属性|数据类型|参数说明| +|:------:|:------:|:------| +| channelId| string| 通道Id| +返回数据: +|属性|数据类型|参数说明| +|:------:|:------:|:------| +| Data| JT808SessionInfoDto | 会话信息对象 | +返回结果: +``` result7 +{ + "Message":"", + "Code":200, + "Data":{ + "ChannelId":"eadad24", + "LastActiveTime":"2018-11-26 20:00:00", + "StartTime":"2018-11-22 20:00:00", + "TerminalPhoneNo":"123456789013" + } +} +``` + +##### 8.通过设备终端号获取会话信息 + +请求地址:Session/GetByTerminalPhoneNo +请求方式:POST +请求参数: +|属性|数据类型|参数说明| +|:------:|:------:|:------| +| terminalPhoneNo| string| 设备终端号| +返回数据: +|属性|数据类型|参数说明| +|:------:|:------:|:------| +| Data| JT808SessionInfoDto | 会话信息对象 | +返回结果: +``` result8 +{ + "Message":"", + "Code":200, + "Data":{ + "ChannelId":"eadad24", + "LastActiveTime":"2018-11-26 20:00:00", + "StartTime":"2018-11-22 20:00:00", + "TerminalPhoneNo":"123456789013" + } +} +``` \ No newline at end of file diff --git a/src/JT808.DotNetty.Hosting/JT808MsgIdCustomHandler.cs b/src/JT808.DotNetty.Hosting/JT808MsgIdCustomHandler.cs index 6dbf591..e4cbbb5 100644 --- a/src/JT808.DotNetty.Hosting/JT808MsgIdCustomHandler.cs +++ b/src/JT808.DotNetty.Hosting/JT808MsgIdCustomHandler.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; -using DotNetty.Transport.Channels; -using JT808.DotNetty.Metadata; -using JT808.Protocol; +using JT808.DotNetty.Metadata; using Microsoft.Extensions.Logging; namespace JT808.DotNetty.Hosting diff --git a/src/JT808.DotNetty.Hosting/Program.cs b/src/JT808.DotNetty.Hosting/Program.cs index a843df9..36280ac 100644 --- a/src/JT808.DotNetty.Hosting/Program.cs +++ b/src/JT808.DotNetty.Hosting/Program.cs @@ -15,8 +15,6 @@ namespace JT808.DotNetty.Hosting { static async Task Main(string[] args) { - //7E 01 02 00 06 01 38 12 34 56 78 00 85 32 31 31 33 31 33 B2 7E - var serverHostBuilder = new HostBuilder() .ConfigureAppConfiguration((hostingContext, config) => { diff --git a/src/JT808.DotNetty/Interfaces/IJT808SessionService.cs b/src/JT808.DotNetty/Interfaces/IJT808SessionService.cs index 4b7dcfa..e08083c 100644 --- a/src/JT808.DotNetty/Interfaces/IJT808SessionService.cs +++ b/src/JT808.DotNetty/Interfaces/IJT808SessionService.cs @@ -26,7 +26,7 @@ namespace JT808.DotNetty.Interfaces /// JT808ResultDto> GetRealAll(); /// - /// 获取设备相关连会话集合 + /// 获取设备相关联会话集合 /// /// JT808ResultDto> GetRelevanceAll(); diff --git a/src/JT808.DotNetty/Internal/JT808SourcePackageDispatcherDefaultImpl.cs b/src/JT808.DotNetty/Internal/JT808SourcePackageDispatcherDefaultImpl.cs index 5f27cfc..b2cc6bc 100644 --- a/src/JT808.DotNetty/Internal/JT808SourcePackageDispatcherDefaultImpl.cs +++ b/src/JT808.DotNetty/Internal/JT808SourcePackageDispatcherDefaultImpl.cs @@ -52,12 +52,12 @@ namespace JT808.DotNetty.Internal } else { - logger.LogError($"{item}链接已关闭"); + logger.LogInformation($"{item} link closed."); } } catch (Exception ex) { - logger.LogError($"{item}发送数据出现异常:{ex}"); + logger.LogError(ex,$"{item} Send Data Error."); } } await Task.CompletedTask; @@ -83,7 +83,8 @@ namespace JT808.DotNetty.Internal DelRemoteServsers(chgRemoteServers); AddRemoteServsers(chgRemoteServers); }); - if (jT808ConfigurationOptionsMonitor.CurrentValue.SourcePackageDispatcherClientConfigurations != null && jT808ConfigurationOptionsMonitor.CurrentValue.SourcePackageDispatcherClientConfigurations.Count > 0) + if (jT808ConfigurationOptionsMonitor.CurrentValue.SourcePackageDispatcherClientConfigurations != null && + jT808ConfigurationOptionsMonitor.CurrentValue.SourcePackageDispatcherClientConfigurations.Count > 0) { foreach (var item in jT808ConfigurationOptionsMonitor.CurrentValue.SourcePackageDispatcherClientConfigurations) { @@ -93,12 +94,12 @@ namespace JT808.DotNetty.Internal { IChannel clientChannel = await bootstrap.ConnectAsync(item.EndPoint); channels.TryAdd(item.EndPoint, clientChannel); - logger.LogInformation($"初始化链接远程服务端{item.EndPoint.ToString()}"); + logger.LogInformation($"init remote link {item.EndPoint.ToString()}."); }); } catch (Exception ex) { - logger.LogError($"初始化链接远程服务端{item},链接异常:{ex}"); + logger.LogError(ex,$"there is an exception in sending data {item}."); } } } @@ -156,11 +157,11 @@ namespace JT808.DotNetty.Internal { IChannel clientChannel =await bootstrap.ConnectAsync(item); channels.TryAdd(item, clientChannel); - logger.LogInformation($"变更后链接远程服务端{item}"); + logger.LogInformation($"link to the remote server after the change {item}."); } catch (Exception ex) { - logger.LogError(ex,$"重连异常变更后链接远程服务端{item}"); + logger.LogError(ex,$"reconnect the remote server after the exception changes {item}."); } } } diff --git a/src/JT808.DotNetty/JT808.DotNetty.csproj b/src/JT808.DotNetty/JT808.DotNetty.csproj index c06b862..b72012c 100644 --- a/src/JT808.DotNetty/JT808.DotNetty.csproj +++ b/src/JT808.DotNetty/JT808.DotNetty.csproj @@ -17,6 +17,14 @@ 1.0.0 + + + + + + E:\koike\My Project\JT808DotNetty\src\JT808.DotNetty\JT808.DotNetty.xml + + diff --git a/src/JT808.DotNetty/JT808WebAPIService.cs b/src/JT808.DotNetty/JT808WebAPIService.cs index 0bfd754..876cb6f 100644 --- a/src/JT808.DotNetty/JT808WebAPIService.cs +++ b/src/JT808.DotNetty/JT808WebAPIService.cs @@ -60,7 +60,8 @@ namespace JT808.DotNetty } /// - /// 会话服务-获取真实连接数 + /// 会话服务-获取实际连接数 + /// 存在其他平台转发过来的数据,这时候通道Id和设备属于一对多的关系 /// /// /// diff --git a/src/doc/README.md b/src/doc/README.md new file mode 100644 index 0000000..b2b4f56 --- /dev/null +++ b/src/doc/README.md @@ -0,0 +1,16 @@ +## 压力测试 + +[感谢泥水佬提供的压力测试工具](https://www.cnblogs.com/smark/p/4496660.html?utm_source=tuicool) + +| 操作系统 | 配置 | 使用 | +|:-------:|:-------:|:-------:| +| win server 2018 | 4c8g | 压力测试客户端 | +| centos7 | 4c8g | JT808服务端 | + +![performance_1000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/performance_1000.png) + +![performance_2000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/performance_2000.png) + +![performance_5000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/performance_5000.png) + +![performance_10000](https://github.com/SmallChi/JT808DotNetty/blob/master/doc/img/performance_5000.png) \ No newline at end of file diff --git a/src/doc/img/design_model.png b/src/doc/img/design_model.png new file mode 100644 index 0000000..c116646 Binary files /dev/null and b/src/doc/img/design_model.png differ diff --git a/src/doc/img/performance_1000.png b/src/doc/img/performance_1000.png new file mode 100644 index 0000000..fb47436 Binary files /dev/null and b/src/doc/img/performance_1000.png differ diff --git a/src/doc/img/performance_10000.png b/src/doc/img/performance_10000.png new file mode 100644 index 0000000..16e9fba Binary files /dev/null and b/src/doc/img/performance_10000.png differ diff --git a/src/doc/img/performance_2000.png b/src/doc/img/performance_2000.png new file mode 100644 index 0000000..4fb945b Binary files /dev/null and b/src/doc/img/performance_2000.png differ diff --git a/src/doc/img/performance_5000.png b/src/doc/img/performance_5000.png new file mode 100644 index 0000000..cf97f7e Binary files /dev/null and b/src/doc/img/performance_5000.png differ