From acd061b9ee66c84550f9338ba26c41274ba92f42 Mon Sep 17 00:00:00 2001 From: cli <377476583@qq.com> Date: Tue, 29 Oct 2024 16:28:14 +0800 Subject: [PATCH] xiugai daima --- JiShe.CollectBus.Common/DataConvert.cs | 176 ---- .../Enums/376Enums.cs | 6 +- .../Enums/CommandChunkEnum.cs | 15 + .../Extensions/HexStringExtensions.cs | 78 ++ .../Extensions/IntExtensions.cs | 30 + .../Extensions/StringExtensions.cs | 173 +++- .../Models/CommandReuslt.cs | 8 +- .../DependencyInjectionExtensions.cs | 6 +- .../JiShe.CollectBus.Console.csproj | 6 + JiShe.CollectBus.Console/Program.cs | 26 +- JiShe.CollectBus.Console/appsettings.json | 27 + JiShe.CollectBus.Core/Plugins/ClosePlugin.cs | 5 +- .../Plugins/TcpServiceReceivedPlugin.cs | 58 +- JiShe.CollectBus.Core/Services/BusService.cs | 15 +- .../Abstracts/BaseProtocolPlugin.cs | 334 +++++++- .../Interfaces/IProtocolPlugin.cs | 9 +- .../Models/MessageReceivedEvent.cs | 23 + .../Models/ReqParameter.cs | 2 + .../TestProtocolPlugin.cs | 7 +- .../StandardProtocolPlugin.cs | 787 +----------------- .../Consumers/MessageIssuedConsumer.cs | 6 +- .../MessageReceivedHeartbeatConsumer.cs | 35 + .../Consumers/MessageReceivedLoginConsumer.cs | 35 + .../JiSheCollectBusRabbitMqModule.cs | 19 +- JiShe.CollectBus.RabbitMQ/Senders/INSender.cs | 4 + JiShe.CollectBus.RabbitMQ/Senders/NSender.cs | 20 + 26 files changed, 910 insertions(+), 1000 deletions(-) delete mode 100644 JiShe.CollectBus.Common/DataConvert.cs rename JiShe.CollectBus.Protocol.Contracts/Models/Enums.cs => JiShe.CollectBus.Common/Enums/376Enums.cs (96%) create mode 100644 JiShe.CollectBus.Common/Enums/CommandChunkEnum.cs create mode 100644 JiShe.CollectBus.Common/Extensions/HexStringExtensions.cs create mode 100644 JiShe.CollectBus.Common/Extensions/IntExtensions.cs rename {JiShe.CollectBus.Protocol.Contracts => JiShe.CollectBus.Common}/Models/CommandReuslt.cs (85%) create mode 100644 JiShe.CollectBus.RabbitMQ/Consumers/MessageReceivedHeartbeatConsumer.cs create mode 100644 JiShe.CollectBus.RabbitMQ/Consumers/MessageReceivedLoginConsumer.cs diff --git a/JiShe.CollectBus.Common/DataConvert.cs b/JiShe.CollectBus.Common/DataConvert.cs deleted file mode 100644 index 71d2fcf..0000000 --- a/JiShe.CollectBus.Common/DataConvert.cs +++ /dev/null @@ -1,176 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; - -namespace JiShe.CollectBus.Common -{ - public class DataConvert - { - /// - /// 十进制转二进制 - /// - /// 十进制数 - /// - public static string DecToBin(int decimalNumber) - { - var binaryString = Convert.ToString(decimalNumber, 2); - return binaryString; - } - - /// - /// 二进制转十六进制 - /// - /// - /// - public static string BinToHex(string binaryString) - { - var decimalNumber = Convert.ToInt32(binaryString, 2);// 将二进制字符串转换为整数 - var hexString = Convert.ToString(decimalNumber, 16); //decimalNumber.ToString("X"); // 将整数转换为十六进制字符串 - return hexString; - } - - /// - /// 十进制转十六进制 - /// - /// - /// - public static string DecToHex(int decimalNumber) - { - var hexString = decimalNumber.ToString("X"); - return hexString; - } - - /// - /// 二进制转十进制 - /// - /// - /// - public static int BinToDec(string binaryString) - { - var decimalNumber = Convert.ToInt32(binaryString, 2); - return decimalNumber; - } - - /// - /// 十六进制转十进制 - /// - /// - /// - public static int HexToDec(string hexString) - { - var decimalNumber = Convert.ToInt32(hexString, 16); - return decimalNumber; - } - - /// - /// 十六进制转二进制 - /// - /// - /// - public static string HexToBin(string hexString) - { - var binaryValue = Convert.ToString(Convert.ToInt32(hexString, 16), 2); - return binaryValue; - } - - - /// - /// 字符串倒序 - /// - /// - /// - public static string StringReversed(string str) - { - var reversed = new string(str.Reverse().ToArray()); - return reversed; - } - - /// - /// 字符串分割成2个字符一组 - /// - /// - /// - public static List StringToPairs(string str) - { - var pairs = str.Select((ch, index) => new { ch, index }) - .GroupBy(x => x.index / 2) - .Select(g => string.Concat(g.Select(x => x.ch))) - .ToList(); - return pairs; - } - - /// - /// 格式化字符串 - /// - /// - /// - public static string StrAddSpan(string str) - { - if (str == "") - { - return ""; - } - return Regex.Replace(str.Replace(" ", ""), @"(?<=[0-9A-Za-z]{2})[0-9A-Za-z]{2}", " $0").Trim(); - } - - /// - /// 格式化字符串且反转 - /// - /// - /// - public static string StrReverseOrder(string ste) - { - if (ste == "") - { - return ""; - } - string[] strArr = ste.Split(new string[] { " " }, System.StringSplitOptions.RemoveEmptyEntries); - - return string.Join(" ", strArr.Reverse()); - } - - /// - /// 数据值加33 - /// - /// - /// - public static string StrAddHex33(string str) - { - if (str == "") - { - return ""; - } - string[] strArr = str.Split(new string[] { " " }, System.StringSplitOptions.RemoveEmptyEntries); - for (int i = 0; i < strArr.Length; i++) - { - strArr[i] = (Convert.ToInt32(strArr[i], 16) + Convert.ToInt32("33", 16)).ToString("X2"); - if (strArr[i].Length > 2) - { - strArr[i] = strArr[i].Substring(strArr[i].Length - 2); - } - } - return string.Join(" ", strArr); - } - - private static string AddHex33(string strGet) - { - string result; - if (string.IsNullOrEmpty(strGet)) - { - result = ""; - } - else - { - string[] source = StrAddSpan(strGet).Split(new char[] - { - ' ' - }, StringSplitOptions.RemoveEmptyEntries); - result = string.Join("", from s in source - select (Convert.ToInt32(s, 16) + Convert.ToInt32("33", 16)).ToString("X2")); - } - return result; - } - - } -} diff --git a/JiShe.CollectBus.Protocol.Contracts/Models/Enums.cs b/JiShe.CollectBus.Common/Enums/376Enums.cs similarity index 96% rename from JiShe.CollectBus.Protocol.Contracts/Models/Enums.cs rename to JiShe.CollectBus.Common/Enums/376Enums.cs index 878d45c..0f10f0d 100644 --- a/JiShe.CollectBus.Protocol.Contracts/Models/Enums.cs +++ b/JiShe.CollectBus.Common/Enums/376Enums.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JiShe.CollectBus.Protocol.Contracts.Models +namespace JiShe.CollectBus.Common.Enums { /// /// 规约标识 高位在前 D1+D0 diff --git a/JiShe.CollectBus.Common/Enums/CommandChunkEnum.cs b/JiShe.CollectBus.Common/Enums/CommandChunkEnum.cs new file mode 100644 index 0000000..55e02fa --- /dev/null +++ b/JiShe.CollectBus.Common/Enums/CommandChunkEnum.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JiShe.CollectBus.Common.Enums +{ + public enum CommandChunkEnum + { + C = 6, + A = 7, + AFN = 12, + SEQ = 13, + FN = 17, + } +} diff --git a/JiShe.CollectBus.Common/Extensions/HexStringExtensions.cs b/JiShe.CollectBus.Common/Extensions/HexStringExtensions.cs new file mode 100644 index 0000000..f223188 --- /dev/null +++ b/JiShe.CollectBus.Common/Extensions/HexStringExtensions.cs @@ -0,0 +1,78 @@ +using JiShe.CollectBus.Common.Enums; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using JiShe.CollectBus.Common.Models; +using System.Runtime.CompilerServices; + +namespace JiShe.CollectBus.Common.Extensions +{ + public static class HexStringExtensions + { + //起始字符 + private const string startStr = "68"; + //结束字符 + private const string endStr = "16"; + //头部字节长度 + private const int hearderLen = 6; + //消息认证码字段长度 + private const int pWLen = 16; + + private const int tPLen = 6; + + private const int FixedLength = 18; + + + public static object GetAnalyzeValue(this List hexStringList, CommandChunkEnum chunk) + { + if (hexStringList.Count < hearderLen || hexStringList[0] != startStr || hexStringList[5] != startStr || hexStringList.Count < FixedLength) + { + return null; + } + + switch (chunk) + { + case CommandChunkEnum.AFN: + var aFn = hexStringList[(int)CommandChunkEnum.AFN].HexToDec();//1字节 + return aFn; + case CommandChunkEnum.FN: + //(DT2*8)+DT1=fn + var dt1Bin = hexStringList[(int)CommandChunkEnum.FN - 1].HexToBin(); + var dt1 = dt1Bin != "0" ? dt1Bin.Length : 0; + var dt2 = hexStringList[(int)CommandChunkEnum.FN].HexToDec(); + var fn = dt2 * 8 + dt1; + return fn; + case CommandChunkEnum.A: + var aHexList = hexStringList.Skip((int)CommandChunkEnum.A).Take(5).ToList(); + var a1 = aHexList[1] + aHexList[0]; + var a2 = aHexList[3] + aHexList[2]; + var a2Dec = a2.HexToDec(); + var a3 = aHexList[4]; + var a = $"{a1}{a2Dec.ToString().PadLeft(5, '0')}"; + var a3Bin = aHexList[4].HexToBin().PadLeft(8, '0'); + var msa = a3Bin.Substring(0, 7).BinToDec(); + return new Tuple(a, msa); + case CommandChunkEnum.SEQ: + var seq = hexStringList[(int)CommandChunkEnum.SEQ].HexToBin().PadLeft(8, '0'); + var tpV = (TpV)Convert.ToInt32(seq.Substring(0, 1)); + var firfin = (FIRFIN)Convert.ToInt32(seq.Substring(1, 2)); + var con = (CON)Convert.ToInt32(seq.Substring(3, 1)); + var prseqBin = seq.Substring(4, 4); + return new Seq + { + CON = con, + FIRFIN = firfin, + PRSEQ = prseqBin.BinToDec(), + TpV = tpV + }; + default: + throw new ArgumentOutOfRangeException(nameof(chunk), chunk, null); + } + } + + + } +} diff --git a/JiShe.CollectBus.Common/Extensions/IntExtensions.cs b/JiShe.CollectBus.Common/Extensions/IntExtensions.cs new file mode 100644 index 0000000..e92a5d9 --- /dev/null +++ b/JiShe.CollectBus.Common/Extensions/IntExtensions.cs @@ -0,0 +1,30 @@ +using System; + +namespace JiShe.CollectBus.Common.Extensions +{ + public static class IntExtensions + { + /// + /// 十进制转二进制 + /// + /// 十进制数 + /// + public static string DecToBin(this int decimalNumber) + { + var binaryString = Convert.ToString(decimalNumber, 2); + return binaryString; + } + + + /// + /// 十进制转十六进制 + /// + /// + /// + public static string DecToHex(this int decimalNumber) + { + var hexString = decimalNumber.ToString("X"); + return hexString; + } + } +} diff --git a/JiShe.CollectBus.Common/Extensions/StringExtensions.cs b/JiShe.CollectBus.Common/Extensions/StringExtensions.cs index 21e9e19..3653956 100644 --- a/JiShe.CollectBus.Common/Extensions/StringExtensions.cs +++ b/JiShe.CollectBus.Common/Extensions/StringExtensions.cs @@ -47,38 +47,6 @@ namespace JiShe.CollectBus.Common.Extensions return string.Copy(str); } - /// Gets the phone number. - /// The string. - /// The pattern. - /// - ///
- ///
- [Description("获取单个手机号")] - public static string GetPhoneNumber(this string str, string pattern = RegexConst.PhoneNumber) - { - var reg = new Regex(pattern); - var match = reg.Match(str); - if (match.Success) - { - return match.Value; - } - return null; - } - - /// Gets the phone numbers. - /// The string. - /// The pattern. - /// - ///
- ///
- [Description("获取全部手机号")] - public static List GetPhoneNumbers(this string str, string pattern = RegexConst.PhoneNumber) - { - var reg = new Regex(pattern); - var matches = reg.Matches(str); - return (from Match item in matches select item.Value).ToList(); - } - /// Regex Match the specified pattern. /// The string. /// The pattern. @@ -1106,6 +1074,147 @@ namespace JiShe.CollectBus.Common.Extensions return string.Join(",", list) == intStr; } + /// + /// 字符串倒序 + /// + /// + /// + public static string StringReversed(this string str) + { + var reversed = new string(str.Reverse().ToArray()); + return reversed; + } + + /// + /// 字符串分割成2个字符一组 + /// + /// + /// + public static List StringToPairs(this string str) + { + var pairs = str.Select((ch, index) => new { ch, index }) + .GroupBy(x => x.index / 2) + .Select(g => string.Concat(g.Select(x => x.ch))) + .ToList(); + return pairs; + } + + /// + /// 格式化字符串 + /// + /// + /// + public static string StrAddSpan(this string str) + { + if (str == "") + { + return ""; + } + return Regex.Replace(str.Replace(" ", ""), @"(?<=[0-9A-Za-z]{2})[0-9A-Za-z]{2}", " $0").Trim(); + } + + /// + /// 格式化字符串且反转 + /// + /// + /// + public static string StrReverseOrder(this string ste) + { + if (ste == "") + { + return ""; + } + string[] strArr = ste.Split(new string[] { " " }, System.StringSplitOptions.RemoveEmptyEntries); + + return string.Join(" ", strArr.Reverse()); + } + + /// + /// 二进制转十六进制 + /// + /// + /// + public static string BinToHex(this string binaryString) + { + var decimalNumber = Convert.ToInt32(binaryString, 2);// 将二进制字符串转换为整数 + var hexString = Convert.ToString(decimalNumber, 16); //decimalNumber.ToString("X"); // 将整数转换为十六进制字符串 + return hexString; + } + + + /// + /// 二进制转十进制 + /// + /// + /// + public static int BinToDec(this string binaryString) + { + var decimalNumber = Convert.ToInt32(binaryString, 2); + return decimalNumber; + } + + /// + /// 十六进制转十进制 + /// + /// + /// + public static int HexToDec(this string hexString) + { + var decimalNumber = Convert.ToInt32(hexString, 16); + return decimalNumber; + } + + /// + /// 十六进制转二进制 + /// + /// + /// + public static string HexToBin(this string hexString) + { + var binaryValue = Convert.ToString(Convert.ToInt32(hexString, 16), 2); + return binaryValue; + } + + /// + /// 数据值加33 + /// + public static string StrAddHex33(this string str) + { + if (str == "") + { + return ""; + } + var strArr = str.Split(new string[] { " " }, System.StringSplitOptions.RemoveEmptyEntries); + for (int i = 0; i < strArr.Length; i++) + { + strArr[i] = (Convert.ToInt32(strArr[i], 16) + Convert.ToInt32("33", 16)).ToString("X2"); + if (strArr[i].Length > 2) + { + strArr[i] = strArr[i].Substring(strArr[i].Length - 2); + } + } + return string.Join(" ", strArr); + } + + private static string AddHex33(this string strGet) + { + string result; + if (string.IsNullOrEmpty(strGet)) + { + result = ""; + } + else + { + string[] source = StrAddSpan(strGet).Split(new char[] + { + ' ' + }, StringSplitOptions.RemoveEmptyEntries); + result = string.Join("", from s in source + select (Convert.ToInt32(s, 16) + Convert.ToInt32("33", 16)).ToString("X2")); + } + return result; + } + private static void CreateAlphaNumMask(StringBuilder buffer, string source, char mask, int length) { for (int i = 0; i < length; i++) diff --git a/JiShe.CollectBus.Protocol.Contracts/Models/CommandReuslt.cs b/JiShe.CollectBus.Common/Models/CommandReuslt.cs similarity index 85% rename from JiShe.CollectBus.Protocol.Contracts/Models/CommandReuslt.cs rename to JiShe.CollectBus.Common/Models/CommandReuslt.cs index 89db4d4..0d75c42 100644 --- a/JiShe.CollectBus.Protocol.Contracts/Models/CommandReuslt.cs +++ b/JiShe.CollectBus.Common/Models/CommandReuslt.cs @@ -1,9 +1,7 @@ -using JiShe.CollectBus.Common; -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; +using System.Collections.Generic; +using JiShe.CollectBus.Common.Enums; -namespace JiShe.CollectBus.Protocol.Contracts.Models +namespace JiShe.CollectBus.Common.Models { //TODO public class CommandReulstMsg diff --git a/JiShe.CollectBus.Console/Extensions/DependencyInjections/DependencyInjectionExtensions.cs b/JiShe.CollectBus.Console/Extensions/DependencyInjections/DependencyInjectionExtensions.cs index 96b7cfd..a2f7992 100644 --- a/JiShe.CollectBus.Console/Extensions/DependencyInjections/DependencyInjectionExtensions.cs +++ b/JiShe.CollectBus.Console/Extensions/DependencyInjections/DependencyInjectionExtensions.cs @@ -5,6 +5,7 @@ using JiShe.CollectBus.Common.Interfaces; using TouchSocket.Core; using Microsoft.Extensions.Hosting; using System; +using Serilog; // ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection @@ -22,7 +23,7 @@ namespace Microsoft.Extensions.DependencyInjection { if (typeof(IJiSheModule).IsAssignableFrom(type) && type is { IsClass: true, IsAbstract: false }) { - + Log.Logger.Information($"正在加载模块{type.Name}..."); var instance = Activator.CreateInstance(type); _ = (type.GetMethod("ConfigureServices")?.Invoke(instance, [services, hostContext])); } @@ -90,6 +91,7 @@ namespace Microsoft.Extensions.DependencyInjection { var attr = type.GetCustomAttribute(); if (attr == null) continue; + Log.Logger.Information($"正在加载插件{attr.Name}..."); var serviceDescriptor = new ServiceDescriptor(interfaceType, attr.Name, type, ServiceLifetime.Singleton); services.Add(serviceDescriptor); } @@ -102,6 +104,7 @@ namespace Microsoft.Extensions.DependencyInjection { var attr = type.GetCustomAttribute(); if (attr == null) continue; + Log.Logger.Information($"正在加载插件{attr.Name}..."); var serviceDescriptor = new ServiceDescriptor(interfaceType, attr.Name, type, ServiceLifetime.Transient); services.Add(serviceDescriptor); } @@ -114,6 +117,7 @@ namespace Microsoft.Extensions.DependencyInjection { var attr = type.GetCustomAttribute(); if (attr == null) continue; + Log.Logger.Information($"正在加载插件{attr.Name}..."); var serviceDescriptor = new ServiceDescriptor(interfaceType, attr.Name, type, ServiceLifetime.Scoped); services.Add(serviceDescriptor); } diff --git a/JiShe.CollectBus.Console/JiShe.CollectBus.Console.csproj b/JiShe.CollectBus.Console/JiShe.CollectBus.Console.csproj index 3fd1a06..1bdd619 100644 --- a/JiShe.CollectBus.Console/JiShe.CollectBus.Console.csproj +++ b/JiShe.CollectBus.Console/JiShe.CollectBus.Console.csproj @@ -30,6 +30,12 @@ + + + + + + diff --git a/JiShe.CollectBus.Console/Program.cs b/JiShe.CollectBus.Console/Program.cs index fcaad3a..5c6c9d5 100644 --- a/JiShe.CollectBus.Console/Program.cs +++ b/JiShe.CollectBus.Console/Program.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Serilog; namespace JiShe.CollectBus.Console { @@ -9,7 +10,23 @@ namespace JiShe.CollectBus.Console static void Main(string[] args) { - CreateHostBuilder(args).Build().Run(); + try + { + Log.Logger = new LoggerConfiguration() + .WriteTo.Console() + .CreateLogger(); + + + CreateHostBuilder(args).Build().Run(); + } + catch (Exception ex) + { + Log.Fatal(ex, "Application terminated unexpectedly"); + } + finally + { + Log.CloseAndFlush(); + } } public static IHostBuilder CreateHostBuilder(string[] args) => @@ -29,9 +46,16 @@ namespace JiShe.CollectBus.Console private static void ConfigureServices(IServiceCollection services, HostBuilderContext hostContext) { var configuration = hostContext.Configuration; + + services.AddSerilog((context, lc) => + { + lc.ReadFrom.Configuration(configuration) + .ReadFrom.Services(context); + }); services.ModuleRegister(hostContext); services.ServiceRegister(); services.PluginServiceRegister(); + services.AddTcp(configuration); //services.AddUdp(configuration); services.AddStackExchangeRedisCache(options => diff --git a/JiShe.CollectBus.Console/appsettings.json b/JiShe.CollectBus.Console/appsettings.json index 4d74af7..72e8a02 100644 --- a/JiShe.CollectBus.Console/appsettings.json +++ b/JiShe.CollectBus.Console/appsettings.json @@ -1,4 +1,31 @@ { + "Serilog": { + "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ], + "MinimumLevel": "Information", + "Override": { + "Microsoft": "Warning", + "System": "Warning" + }, + "WriteTo": [ + { "Name": "Console" }, + { + "Name": "File", + "Args": { + "path": "Logs/log-.txt", + "rollingInterval": "Day" + //"rollOnFileSizeLimit": true, + //"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact" + } + } + ], + "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ], + + "Properties": { + "Application": "CollectBus", + "Environment": "Development" + } + }, + "ConnectionStrings": { "Default": "Data Source=192.168.111.248;Port=3306;Database=JiSheCollectBus;uid=root;pwd=123456abcD;charset=utf8mb4;Allow User Variables=true;AllowLoadLocalInfile=true", "ClickHouse": "host=localhost;port=8123;user=default;password=;database=default" diff --git a/JiShe.CollectBus.Core/Plugins/ClosePlugin.cs b/JiShe.CollectBus.Core/Plugins/ClosePlugin.cs index df99a94..b0c0531 100644 --- a/JiShe.CollectBus.Core/Plugins/ClosePlugin.cs +++ b/JiShe.CollectBus.Core/Plugins/ClosePlugin.cs @@ -1,10 +1,11 @@ using JiShe.CollectBus.Core.Exceptions; +using Microsoft.Extensions.Logging; using TouchSocket.Core; using TouchSocket.Sockets; namespace JiShe.CollectBus.Core.Plugins { - public partial class TcpClosePlugin(ILog logger) : PluginBase + public partial class TcpClosePlugin(ILogger logger) : PluginBase { [GeneratorPlugin(typeof(ITcpReceivedPlugin))] public async Task OnTcpReceived(ITcpSessionClient client, ReceivedDataEventArgs e) @@ -15,7 +16,7 @@ namespace JiShe.CollectBus.Core.Plugins } catch (CloseException ex) { - logger.Info("拦截到CloseException"); + logger.LogInformation("拦截到CloseException"); client.Close(ex.Message); } catch (Exception exx) diff --git a/JiShe.CollectBus.Core/Plugins/TcpServiceReceivedPlugin.cs b/JiShe.CollectBus.Core/Plugins/TcpServiceReceivedPlugin.cs index 1b463e4..9cb8fc3 100644 --- a/JiShe.CollectBus.Core/Plugins/TcpServiceReceivedPlugin.cs +++ b/JiShe.CollectBus.Core/Plugins/TcpServiceReceivedPlugin.cs @@ -1,17 +1,23 @@ -using JiShe.CollectBus.Protocol.Contracts.Models; +using JiShe.CollectBus.Common.Enums; +using JiShe.CollectBus.Common.Extensions; +using JiShe.CollectBus.Protocol.Contracts.Models; using TouchSocket.Core; using TouchSocket.Sockets; using JiShe.CollectBus.RabbitMQ.Senders; +using Microsoft.Extensions.Logging; namespace JiShe.CollectBus.Core.Plugins { public partial class TcpServiceReceivedPlugin : PluginBase { private readonly INSender _nSender; + private readonly ILogger _logger; - public TcpServiceReceivedPlugin(INSender nSender) + + public TcpServiceReceivedPlugin(INSender nSender, ILogger logger) { _nSender = nSender; + _logger = logger; } @@ -32,29 +38,55 @@ namespace JiShe.CollectBus.Core.Plugins //client.Logger.Info($"[TCP] 已从{client.GetIPPort()}接收到信息:{messageHexString}"); //await protocolPlugin.ReceivedAsync(client,e); - await _nSender.SendToReceivedAsync(new MessageReceivedEvent + + var messageHexString = Convert.ToHexString(e.ByteBlock.Span); + var hexStringList = messageHexString.StringToPairs(); + var aFn = (int?)hexStringList.GetAnalyzeValue(CommandChunkEnum.AFN); + var fn = (int?)hexStringList.GetAnalyzeValue(CommandChunkEnum.FN); + + if (aFn.HasValue && fn.HasValue) { - ClientIP = client.IP, - ClientId = client.Id, - MessageHexString = Convert.ToHexString(e.ByteBlock.Span), - Port = client.Port - }); + if ((AFN)aFn == AFN.链路接口检测) + { + switch (fn) + { + case 1://登录 + await _nSender.SendToReceivedLoginAsync(new MessageReceivedLoginEvent(client.Id,client.IP, client.Port, messageHexString,"")); + break; + case 2://退出登录 + await _nSender.SendToReceivedLoginAsync(new MessageReceivedLoginEvent(client.Id, client.IP, client.Port, messageHexString, "")); + break; + case 3://心跳 + await _nSender.SendToReceivedHeartbeatAsync(new MessageReceivedHeartbeatEvent(client.Id, client.IP, client.Port, messageHexString, "")); + break; + } + } + else + { + await _nSender.SendToReceivedAsync(new MessageReceivedEvent(client.Id, client.IP, client.Port, messageHexString, "")); + } + } + else + { + _logger.LogError($"指令初步解析失败,指令内容:{messageHexString}"); + } + await e.InvokeNext(); } [GeneratorPlugin(typeof(ITcpConnectingPlugin))] - public async Task OnTcpConnecting(ITcpSessionClient client, ConnectingEventArgs e) + public async Task OnTcpConnecting(ITcpSessionClient client,ConnectingEventArgs e) { - client.Logger.Info($"[TCP] ID:{client.Id} IP:{client.GetIPPort()}正在连接中..."); + _logger.LogInformation($"[TCP] ID:{client.Id} IP:{client.GetIPPort()}正在连接中..."); await e.InvokeNext(); } [GeneratorPlugin(typeof(ITcpConnectedPlugin))] - public async Task OnTcpConnected(ITcpSessionClient client, ConnectedEventArgs e) + public async Task OnTcpConnected(ITcpSessionClient client,ConnectedEventArgs e) { - client.Logger.Info($"[TCP] ID:{client.Id} IP:{client.GetIPPort()}已连接"); + _logger.LogInformation($"[TCP] ID:{client.Id} IP:{client.GetIPPort()}已连接"); await e.InvokeNext(); } @@ -62,7 +94,7 @@ namespace JiShe.CollectBus.Core.Plugins [GeneratorPlugin(typeof(ITcpClosedPlugin))] public async Task OnTcpClosed(ITcpSessionClient client, ClosedEventArgs e) { - client.Logger.Info($"[TCP] ID:{client.Id} IP:{client.GetIPPort()}已关闭连接"); + _logger.LogInformation($"[TCP] ID:{client.Id} IP:{client.GetIPPort()}已关闭连接"); await e.InvokeNext(); } diff --git a/JiShe.CollectBus.Core/Services/BusService.cs b/JiShe.CollectBus.Core/Services/BusService.cs index 9f1253e..f8419a2 100644 --- a/JiShe.CollectBus.Core/Services/BusService.cs +++ b/JiShe.CollectBus.Core/Services/BusService.cs @@ -1,4 +1,5 @@ -using System; +using Microsoft.Extensions.Logging; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -8,7 +9,7 @@ using TouchSocket.Sockets; namespace JiShe.CollectBus.Core.Services { - public partial class BusService : PluginBase + public partial class BusService(ILogger logger) : PluginBase { [GeneratorPlugin(typeof(IServerStartedPlugin))] public Task OnServerStarted(IServiceBase sender, ServiceStateEventArgs e) @@ -19,26 +20,26 @@ namespace JiShe.CollectBus.Core.Services { foreach (var item in service.Monitors) { - ConsoleLogger.Default.Info($"TCP {item.Option.IpHost}"); + logger.LogInformation($"TCP {item.Option.IpHost}"); } break; } case UdpSession session: - ConsoleLogger.Default.Info($"UDP {session.Monitor.IPHost}"); + logger.LogInformation($"UDP {session.Monitor.IPHost}"); break; } - ConsoleLogger.Default.Info(e.ServerState == ServerState.Running + logger.LogInformation(e.ServerState == ServerState.Running ? $"服务器成功启动" : $"服务器启动失败,状态:{e.ServerState},异常:{e.Exception}"); return e.InvokeNext(); } [GeneratorPlugin(typeof(IServerStopedPlugin))] - public Task OnServerStoped(IServiceBase sender, ServiceStateEventArgs e) + public Task OnServerStoped(IServiceBase sender,ServiceStateEventArgs e) { - Console.WriteLine("服务已停止"); + logger.LogInformation("服务已停止"); return e.InvokeNext(); } } diff --git a/JiShe.CollectBus.Protocol.Contracts/Abstracts/BaseProtocolPlugin.cs b/JiShe.CollectBus.Protocol.Contracts/Abstracts/BaseProtocolPlugin.cs index 8a700d9..8427949 100644 --- a/JiShe.CollectBus.Protocol.Contracts/Abstracts/BaseProtocolPlugin.cs +++ b/JiShe.CollectBus.Protocol.Contracts/Abstracts/BaseProtocolPlugin.cs @@ -1,13 +1,343 @@ -using System.Threading.Tasks; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using JiShe.CollectBus.Common; +using JiShe.CollectBus.Common.Enums; +using JiShe.CollectBus.Common.Extensions; +using JiShe.CollectBus.Common.Models; using JiShe.CollectBus.Protocol.Contracts.Interfaces; using JiShe.CollectBus.Protocol.Contracts.Models; +using Microsoft.Extensions.Logging; namespace JiShe.CollectBus.Protocol.Contracts.Abstracts { public abstract class BaseProtocolPlugin : IProtocolPlugin { + public readonly ILogger _logger; + //起始字符 + public const string stx = "68"; + //结束字符 + public const string end = "16"; + //头部字节长度 + public const int hearderLen = 6; + //消息认证码字段长度 + public const int pWLen = 16; + + public const int tPLen = 6; + + + protected BaseProtocolPlugin(ILogger logger) + { + _logger = logger; + } + public abstract Task GetAsync(); - public abstract Task AnalyzeAsync(MessageReceivedEvent messageReceivedEvent); + public abstract Task AnalyzeAsync(MessageReceivedEvent messageReceivedEvent, Action? sendAction = null); + + /// + /// 登录帧解析 + /// + /// 报文 + /// 发送委托 + /// + public virtual Task LoginAsync(MessageReceivedLoginEvent messageReceivedEvent, Action? sendAction = null) + { + var hexStringList = messageReceivedEvent.MessageHexString.StringToPairs(); + var aTuple = (Tuple)hexStringList.GetAnalyzeValue(CommandChunkEnum.A); + var seq = (Seq)hexStringList.GetAnalyzeValue(CommandChunkEnum.SEQ); + var reqParam = new ReqParameter2 + { + AFN = AFN.确认或否认, + FunCode = (int)CFromStationFunCode.链路数据, + PRM = PRM.从动站报文, + A = aTuple.Item1, + Seq = new Seq() + { + TpV = TpV.附加信息域中无时间标签, + FIRFIN = FIRFIN.单帧, + CON = CON.需要对该帧进行确认, + PRSEQ = seq.PRSEQ + }, + MSA = aTuple.Item2, + Pn = 0, + Fn = 1 + }; + var bytes = GetCommandBytes(reqParam); + if (sendAction != null) + { + sendAction(bytes); + } + return Task.CompletedTask; + } + + /// + /// 心跳帧解析 + /// + /// 报文 + /// 发送委托 + /// + public virtual Task HeartbeatAsync(MessageReceivedHeartbeatEvent messageReceivedEvent, Action? sendAction = null) + { + var hexStringList = messageReceivedEvent.MessageHexString.StringToPairs(); + var aTuple = (Tuple)hexStringList.GetAnalyzeValue(CommandChunkEnum.A); + var seq = (Seq)hexStringList.GetAnalyzeValue(CommandChunkEnum.SEQ); + if (seq.TpV == TpV.附加信息域中带时间标签) + { + //解析 + + } + if (seq.CON == CON.需要对该帧进行确认) + { + var reqParam = new ReqParameter2() + { + AFN = AFN.确认或否认, + FunCode = (int)CFromStationFunCode.链路数据, + PRM = PRM.从动站报文, + A = aTuple.Item1, + Seq = new Seq() + { + TpV = TpV.附加信息域中无时间标签, + FIRFIN = FIRFIN.单帧, + CON = CON.不需要对该帧进行确认, + PRSEQ = seq.PRSEQ, + }, + MSA = aTuple.Item2, + Pn = 0, + Fn = 1 + }; + var bytes = GetCommandBytes(reqParam); + if (sendAction != null) + { + sendAction(bytes); + } + } + return Task.CompletedTask; + } + + + #region 通用解析 + + public byte[] GetCommandBytes(ReqParameter reqParameter, List? dataUnit = null) + { + var cmdStrList = new List(); + var userDatas = GetUserData(reqParameter, dataUnit); + var hearders = GetHeaders(userDatas.Count); + var cs = GetCS(userDatas); + cmdStrList.AddRange(hearders); + cmdStrList.AddRange(userDatas); + cmdStrList.Add(cs); + cmdStrList.Add(end); + _logger.LogInformation($"回复:{string.Join(" ", cmdStrList)}"); + var bytes = cmdStrList.Select(x => Convert.ToByte(x, 16)).ToArray(); + return bytes; + } + + /// + /// 帧校验和 + /// + /// 用户数据区 + /// + public string GetCS(List userData) + { + byte sum = 0; + foreach (var d in userData) + { + var b = Convert.ToByte(d, 16); + sum += b; + } + return sum.ToString("X2"); + } + + /// + /// 用户数据区 + /// + /// + /// + public List GetUserData(ReqParameter reqParameter, List? dataUnit) + { + var c = GetC(reqParameter.FunCode, reqParameter.PRM); + var a = GetAList(reqParameter.A, reqParameter.MSA); + + var linkUserData = GetLinkUserData(reqParameter.AFN, reqParameter.Seq, + ((ReqParameter2)reqParameter).Pn, ((ReqParameter2)reqParameter).Fn, dataUnit); + + var list = new List() { c }; + list.AddRange(a); + list.AddRange(linkUserData); + return list; + } + + /// + /// 固定长度的报文头 起始字符+长度+长度+起始字符 + /// + /// + /// + public List GetHeaders(int length) + { + var headers = new List(); + headers.Add(stx); + var l = GetLength(length); + headers.AddRange(l); + headers.AddRange(l); + headers.Add(stx); + return headers; + } + + /// + /// 长度 2字节 [用户数据区长度] + /// + /// + public List GetLength(int length1) + { + var binaryLen = length1.DecToBin(); + var protocolIdentification = Enum.Format(typeof(ProtocolIdentification), + ProtocolIdentification.本规约使用, "d").PadLeft(2, '0'); + var lenStr = $"{binaryLen}{protocolIdentification}"; + var hexLen = lenStr.BinToHex(); + hexLen = hexLen.PadLeft(4, '0'); + var list = hexLen.StringToPairs(); + list.Reverse(); + return list; + } + + /// + /// 控制域 + /// + /// 功能码 + /// + /// + /// + public string GetC(int funCode, PRM pRM, int fcb = 0, FCV fcv = FCV.FCB位无效) + { + var cMasterStationFunCodeHex = funCode.DecToBin(); + cMasterStationFunCodeHex = cMasterStationFunCodeHex.ToString().PadLeft(4, '0'); + var strC = $"{(int)DIR.主站下行报文}{(int)pRM}{fcb}{(int)fcv}{cMasterStationFunCodeHex}"; + var hexC = strC.BinToHex().PadLeft(2, '0'); + return hexC; + } + + + /// + /// 地址域 3220 09872 + /// + /// 行政区划码 BCD码 3220=2032 + /// 逻辑地址 BIN 09872=2690=>9026 + /// 主站地址 BIN 0~127 + /// + public List GetAList(string a, int mSA) + { + var list = new List(); + + var a1 = a.Substring(0, 4); + var a1Pairs = a1.StringToPairs(); + a1Pairs.Reverse(); + list.AddRange(a1Pairs); + + var a2 = Convert.ToInt32(a.Substring(4)); + var decA2 = a2.DecToHex(); + var a2Pairs = decA2.PadLeft(4, '0').StringToPairs(); + a2Pairs.Reverse(); + list.AddRange(a2Pairs); + + //TODO:主站地址和组地址标志 + var a3Bin = $"{mSA.DecToBin().PadLeft(7, '0')}0"; + list.Add(a3Bin.BinToHex().PadLeft(2, '0')); + + return list; + } + + public List GetLinkUserData(AFN aFN, Seq seq, int pn, int fn, List? dataUnit) + { + var aFNValue = ((int)aFN).DecToHex().PadLeft(2, '0'); + var sEQ = GetSEQ(seq.TpV, seq.FIRFIN, seq.CON, seq.PRSEQ); + var dA = GetDA(pn); + var dT = GetDT(fn); + var list = new List() { aFNValue, sEQ }; + list.AddRange(dA); + list.AddRange(dT); + + if (dataUnit != null) + { + list.AddRange(dataUnit); + } + //list.AddRange(GetDataUnit(aFN,seq)); + + if (seq.TpV == TpV.附加信息域中带时间标签) + list.AddRange(GetTp("00")); + + return list; + } + + /// + /// 帧序列域 + /// + /// + /// + /// + /// + public string GetSEQ(TpV tpV, FIRFIN fIRFIN, CON cON, int pRSEQ) + { + var tpVValue = Enum.Format(typeof(TpV), + tpV, "d"); + var fIRFINValue = Enum.Format(typeof(FIRFIN), + fIRFIN, "d"); + var cONValue = (int)cON; + var sEQBin = $"{tpVValue}{fIRFINValue}{cONValue}{pRSEQ.DecToBin().PadLeft(4, '0')}"; + var hexSEQ = sEQBin.BinToHex().PadLeft(2, '0'); + return hexSEQ; + } + + /// + /// 信息点标识 + /// + /// 计量点 + /// + public List GetDA(int pn) + { + if (pn == 0) + return new List() { "00", "00" }; + var dA2 = (pn - 1) / 8 + 1;//信息点组从1开始 第几组 + var dA1 = pn - (dA2 - 1) * 8;//pn % 8 + var dA1Hex = "1".PadRight(dA1, '0').BinToHex();//对位信息 第几位 二进制有效位 + var dA2Hex = dA2.DecToHex(); + return new List() { dA1Hex.PadLeft(2, '0'), dA2Hex.PadLeft(2, '0') }; + + } + + /// + /// 数据单元标识 + /// + /// + /// + public List GetDT(int fn) + { + var dT2 = (fn - 1) / 8;//从零开始 第几组 + var dT1 = fn - dT2 * 8; + var dT1Hex = "1".PadRight(dT1, '0').BinToHex();//对位信息 第几位 二进制有效位 + var dT2Hex = dT2.DecToHex(); + return new List() { dT1Hex.PadLeft(2, '0'), dT2Hex.PadLeft(2, '0') }; + } + + /// + /// 时间标签 + /// + /// 启动帧帧序号计数器PFC 1字节 + /// 允许发送传输延时时间 min 1字节 + /// + public List GetTp(string pFC = "00", int delayTime = 0) + { + + var now = DateTime.Now; // 获取当前时间 + var seconds = now.Second.ToString().PadLeft(2, '0'); // 获取当前秒数 + var minutes = now.Minute.ToString().PadLeft(2, '0'); // 获取当前分钟数 + var hours = now.Hour.ToString().PadLeft(2, '0'); // 获取当前小时数 + var day = now.Day.ToString().PadLeft(2, '0'); // 获取当前日期的日数 + return new List() { pFC, seconds, minutes, hours, day, delayTime.ToString().PadLeft(2, '0') }; + } + + #endregion + } } diff --git a/JiShe.CollectBus.Protocol.Contracts/Interfaces/IProtocolPlugin.cs b/JiShe.CollectBus.Protocol.Contracts/Interfaces/IProtocolPlugin.cs index 6eadf7e..66105cc 100644 --- a/JiShe.CollectBus.Protocol.Contracts/Interfaces/IProtocolPlugin.cs +++ b/JiShe.CollectBus.Protocol.Contracts/Interfaces/IProtocolPlugin.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using JiShe.CollectBus.Protocol.Contracts.Models; using TouchSocket.Sockets; @@ -8,6 +9,10 @@ namespace JiShe.CollectBus.Protocol.Contracts.Interfaces { Task GetAsync(); - Task AnalyzeAsync(MessageReceivedEvent messageReceivedEvent); + Task AnalyzeAsync(MessageReceivedEvent messageReceivedEvent, Action? sendAction = null); + + Task LoginAsync(MessageReceivedLoginEvent messageReceivedEvent, Action? sendAction = null); + + Task HeartbeatAsync(MessageReceivedHeartbeatEvent messageReceivedEvent, Action? sendAction = null); } } diff --git a/JiShe.CollectBus.Protocol.Contracts/Models/MessageReceivedEvent.cs b/JiShe.CollectBus.Protocol.Contracts/Models/MessageReceivedEvent.cs index 87e093d..5a6aa3c 100644 --- a/JiShe.CollectBus.Protocol.Contracts/Models/MessageReceivedEvent.cs +++ b/JiShe.CollectBus.Protocol.Contracts/Models/MessageReceivedEvent.cs @@ -2,6 +2,15 @@ { public class MessageReceivedEvent { + public MessageReceivedEvent(string clientId, string clientIp,int port, string messageHexString, string deviceNo) + { + ClientId = clientId; + ClientIP = clientIp; + Port = port; + MessageHexString = messageHexString; + DeviceNo = deviceNo; + } + /// /// 客服端标识 /// @@ -27,4 +36,18 @@ ///
public string DeviceNo { get; set; } } + + public class MessageReceivedLoginEvent: MessageReceivedEvent + { + public MessageReceivedLoginEvent(string clientId, string clientIp, int port, string messageHexString, string deviceNo) : base(clientId, clientIp, port, messageHexString, deviceNo) + { + } + } + + public class MessageReceivedHeartbeatEvent : MessageReceivedEvent + { + public MessageReceivedHeartbeatEvent(string clientId, string clientIp, int port, string messageHexString, string deviceNo) : base(clientId, clientIp, port, messageHexString, deviceNo) + { + } + } } diff --git a/JiShe.CollectBus.Protocol.Contracts/Models/ReqParameter.cs b/JiShe.CollectBus.Protocol.Contracts/Models/ReqParameter.cs index 00503fb..dfee33e 100644 --- a/JiShe.CollectBus.Protocol.Contracts/Models/ReqParameter.cs +++ b/JiShe.CollectBus.Protocol.Contracts/Models/ReqParameter.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.Net.Sockets; using System.Text; using JiShe.CollectBus.Common; +using JiShe.CollectBus.Common.Enums; +using JiShe.CollectBus.Common.Models; namespace JiShe.CollectBus.Protocol.Contracts.Models { diff --git a/JiShe.CollectBus.Protocol.Test/TestProtocolPlugin.cs b/JiShe.CollectBus.Protocol.Test/TestProtocolPlugin.cs index 13d6c87..b1f43b8 100644 --- a/JiShe.CollectBus.Protocol.Test/TestProtocolPlugin.cs +++ b/JiShe.CollectBus.Protocol.Test/TestProtocolPlugin.cs @@ -3,6 +3,7 @@ using JiShe.CollectBus.Protocol.Contracts.Abstracts; using JiShe.CollectBus.Protocol.Contracts.Attributes; using JiShe.CollectBus.Protocol.Contracts.Models; using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Logging; using TouchSocket.Sockets; namespace JiShe.CollectBus.Protocol.Test @@ -10,12 +11,16 @@ namespace JiShe.CollectBus.Protocol.Test [ProtocolName("TestProtocol")] public class TestProtocolPlugin : BaseProtocolPlugin, ISingletonDependency { + public TestProtocolPlugin(ILogger logger) : base(logger) + { + } + public override Task GetAsync() { throw new NotImplementedException(); } - public override Task AnalyzeAsync(MessageReceivedEvent messageReceivedEvent) + public override Task AnalyzeAsync(MessageReceivedEvent messageReceivedEvent, Action? sendAction = null) { throw new NotImplementedException(); } diff --git a/JiShe.CollectBus.Protocol/StandardProtocolPlugin.cs b/JiShe.CollectBus.Protocol/StandardProtocolPlugin.cs index ad49e01..a47505a 100644 --- a/JiShe.CollectBus.Protocol/StandardProtocolPlugin.cs +++ b/JiShe.CollectBus.Protocol/StandardProtocolPlugin.cs @@ -1,53 +1,29 @@ using JiShe.CollectBus.Common; +using JiShe.CollectBus.Common.Enums; +using JiShe.CollectBus.Common.Extensions; using JiShe.CollectBus.Common.Extensions.DependencyInjections; +using JiShe.CollectBus.Common.Models; using JiShe.CollectBus.Protocol.Contracts.Abstracts; using JiShe.CollectBus.Protocol.Contracts.Attributes; using JiShe.CollectBus.Protocol.Contracts.Models; using JiShe.CollectBus.RabbitMQ.Senders; using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Logging; using TouchSocket.Sockets; namespace JiShe.CollectBus.Protocol { [ProtocolName("StandardProtocol")] - public class StandardProtocolPlugin(INSender nSender) : BaseProtocolPlugin, ISingletonDependency + public class StandardProtocolPlugin(INSender nSender, ILogger logger) : BaseProtocolPlugin(logger), ISingletonDependency { - //起始字符 - private const string stx = "68"; - //结束字符 - private const string end = "16"; - //头部字节长度 - private const int hearderLen = 6; - //消息认证码字段长度 - private const int pWLen = 16; - - private const int tPLen = 6; - - static object locker = new object(); - static List MSA = new List(); - static Dictionary> usingMSA = new Dictionary>(); - - private string clientId = ""; - - static StandardProtocolPlugin() - { - for (int i = 1; i <= 127; i++) - { - MSA.Add(i); - } - } - - public override async Task GetAsync() { var info = new ProtocolInfo("Standard", "376.1", "TCP", "376.1协议", "DTS1980"); return await Task.FromResult(info); } - public override async Task AnalyzeAsync(MessageReceivedEvent messageReceivedEvent) + public override async Task AnalyzeAsync(MessageReceivedEvent messageReceivedEvent, Action? sendAction = null) { - clientId = messageReceivedEvent.ClientId; - var cmdResult = AnalysisCmd(messageReceivedEvent.MessageHexString); if (cmdResult == null) { @@ -57,29 +33,32 @@ namespace JiShe.CollectBus.Protocol await Task.CompletedTask; } - /// - /// Gets the msa. - /// - /// The mark. - /// - public static int GetMSA(string mark) + public override async Task LoginAsync(MessageReceivedLoginEvent messageReceivedEvent, Action? sendAction = null) { - lock (locker) + async void SendAction(byte[] bytes) { - if (!usingMSA.Keys.Contains(mark)) - usingMSA.Add(mark, new List()); - - int msa = MSA.Except(usingMSA[mark]).FirstOrDefault(); - //if (msa == 1) msa = 2;//msa=1为自定义指令保留 - usingMSA[mark].Add(msa); - - if (msa == 127) - usingMSA[mark].RemoveAll(m => true); - - return msa; + await nSender.SendToIssuedAsync(new MessageIssuedEvent { ClientId = messageReceivedEvent.ClientId, DeviceNo = messageReceivedEvent.DeviceNo, Message = bytes }); } + + await base.LoginAsync(messageReceivedEvent, SendAction); } + + public override async Task HeartbeatAsync(MessageReceivedHeartbeatEvent messageReceivedEvent, Action? sendAction = null) + { + async void SendAction(byte[] bytes) + { + await nSender.SendToIssuedAsync(new MessageIssuedEvent { ClientId = messageReceivedEvent.ClientId, DeviceNo = messageReceivedEvent.DeviceNo, Message = bytes }); + } + await base.HeartbeatAsync(messageReceivedEvent, SendAction); + } + + + + + + + #region 上行命令 //68 @@ -112,7 +91,7 @@ namespace JiShe.CollectBus.Protocol public CommandReulst? AnalysisCmd(string cmd) { CommandReulst? commandReulst = null; - var hexStringList = DataConvert.StringToPairs(cmd); + var hexStringList = cmd.StringToPairs(); if (hexStringList.Count < hearderLen) { @@ -125,8 +104,8 @@ namespace JiShe.CollectBus.Protocol } var lenHexStr = $"{hexStringList[2]}{hexStringList[1]}"; - var lenBin = DataConvert.HexToBin(lenHexStr); - var len = DataConvert.BinToDec(lenBin.Remove(lenBin.Length - 2)); + var lenBin = lenHexStr.HexToBin(); + var len = lenBin.Remove(lenBin.Length - 2).BinToDec(); //验证长度 if (hexStringList.Count - 2 != hearderLen + len) return commandReulst; @@ -137,14 +116,14 @@ namespace JiShe.CollectBus.Protocol var aHexList = hexStringList.Skip(userDataIndex).Take(5).ToList();//地址域 5字节 var a = AnalysisA(aHexList); - var a3Bin = DataConvert.HexToBin(aHexList[4]).PadLeft(8, '0'); - var mSA = DataConvert.BinToDec(a3Bin.Substring(0, 7)); + var a3Bin = aHexList[4].HexToBin().PadLeft(8, '0'); + var mSA = a3Bin.Substring(0, 7).BinToDec(); userDataIndex += 5; - var aFN = (AFN)DataConvert.HexToDec(hexStringList[userDataIndex]);//1字节 + var aFN = (AFN)hexStringList[userDataIndex].HexToDec();//1字节 userDataIndex += 1; - var seq = DataConvert.HexToBin(hexStringList[userDataIndex]).PadLeft(8, '0'); + var seq = hexStringList[userDataIndex].HexToBin().PadLeft(8, '0'); var tpV = (TpV)Convert.ToInt32(seq.Substring(0, 1)); var fIRFIN = (FIRFIN)Convert.ToInt32(seq.Substring(1, 2)); var cON = (CON)Convert.ToInt32(seq.Substring(3, 1)); @@ -152,20 +131,19 @@ namespace JiShe.CollectBus.Protocol userDataIndex += 1; // (DA2 - 1) * 8 + DA1 = pn - var da1Bin = DataConvert.HexToBin(hexStringList[userDataIndex]); + var da1Bin = hexStringList[userDataIndex].HexToBin(); var da1 = da1Bin == "0" ? 0 : da1Bin.Length; userDataIndex += 1; - var da2 = DataConvert.HexToDec(hexStringList[userDataIndex]); - userDataIndex += 1; + var da2 = hexStringList[userDataIndex].HexToDec(); var pn = da2 == 0 ? 0 : (da2 - 1) * 8 + da1; - + userDataIndex += 1; //(DT2*8)+DT1=fn - var dt1Bin = DataConvert.HexToBin(hexStringList[userDataIndex]); + var dt1Bin = hexStringList[userDataIndex].HexToBin(); var dt1 = dt1Bin != "0" ? dt1Bin.Length : 0; userDataIndex += 1; - var dt2 = DataConvert.HexToDec(hexStringList[userDataIndex]); - userDataIndex += 1; + var dt2 = hexStringList[userDataIndex].HexToDec(); var fn = dt2 * 8 + dt1; + userDataIndex += 1; //数据单元 var datas = hexStringList.Skip(userDataIndex).Take(len + hearderLen - userDataIndex).ToList(); @@ -182,7 +160,7 @@ namespace JiShe.CollectBus.Protocol TpV = tpV, FIRFIN = fIRFIN, CON = cON, - PRSEQ = DataConvert.BinToDec(prseqBin), + PRSEQ = prseqBin.BinToDec(), }, CmdLength = len, Pn = pn, @@ -202,7 +180,7 @@ namespace JiShe.CollectBus.Protocol { var a1 = aHexList[1] + aHexList[0]; var a2 = aHexList[3] + aHexList[2]; - var a2Dec = DataConvert.HexToDec(a2); + var a2Dec = a2.HexToDec(); var a3 = aHexList[4]; var a = $"{a1}{a2Dec.ToString().PadLeft(5, '0')}"; return a; @@ -285,12 +263,6 @@ namespace JiShe.CollectBus.Protocol Fn = 1 }; commandReulst.ReplyBytes = GetCommandBytes(reqParam); - nSender.SendToIssuedAsync(new MessageIssuedEvent - { - ClientId = clientId, - DeviceNo = "", - Message = commandReulst.ReplyBytes - }); } else if (commandReulst.Fn == 2)//退出登录 { @@ -332,681 +304,6 @@ namespace JiShe.CollectBus.Protocol commandReulst.ReplyBytes = GetCommandBytes(reqParam); } } - - /// - /// 解析时间标签 - /// - /// - private void AnalysisTp(List hexDatas) - { - var pFC = DataConvert.HexToDec(hexDatas[0]);//启动帧帧序号计数器 - var seconds = Convert.ToInt32(hexDatas[1]); // 获取当前秒数 - var minutes = Convert.ToInt32(hexDatas[2]); // 获取当前分钟数 - var hours = Convert.ToInt32(hexDatas[3]); // 获取当前小时数 - var day = Convert.ToInt32(hexDatas[4]); // 获取当前日期的日数 - var delayTime = DataConvert.HexToDec(hexDatas[5]);//延迟时间 min - } - - /// - /// 解析电表档案 - /// - /// - /// - public List AnalysisAFN04F10DataUnit(List hexDatas) - { - var meterList = new List(); - var count = DataConvert.HexToDec($"{hexDatas[1]}{hexDatas[0]}"); - //if (2 + count * 27 != hexDatas.Count - pWLen - tPLen - 2) - // return; - var index = 2;//数量 - for (int i = 1; i <= count; i++) - { - var meterNumber = DataConvert.HexToDec($"{hexDatas[index + 1]}{hexDatas[index]}"); - index += 2; - - var pn = DataConvert.HexToDec($"{hexDatas[index + 1]}{hexDatas[index]}"); - index += 2; - - var baudRateAndPortBin = DataConvert.HexToBin(hexDatas[index]).PadLeft(8, '0'); - var baudRate = DataConvert.BinToDec(baudRateAndPortBin.Substring(0, 3)); - var port = DataConvert.BinToDec(baudRateAndPortBin.Substring(3, 5)); - index += 1; - - var protocolType = (CommunicationProtocolType)DataConvert.HexToDec(hexDatas[index]); - index += 1; - - var addressHexList = hexDatas.Skip(index).Take(6).ToList(); - addressHexList.Reverse(); - var address = string.Join("", addressHexList); - index += 6; - - var pwdHexList = hexDatas.Skip(index).Take(6).ToList(); - pwdHexList.Reverse(); - var password = string.Join("", pwdHexList.Take(3).ToList()); - index += 6; - - var rateNumberBin = DataConvert.HexToBin(hexDatas[index]).PadLeft(8, '0'); - var rateNumber = DataConvert.BinToDec(rateNumberBin.Substring(4)); - index += 1; - - var intBitAndDecBitNumberBin = DataConvert.HexToBin(hexDatas[index]).PadLeft(8, '0'); - var intBitNumber = DataConvert.BinToDec(intBitAndDecBitNumberBin.Substring(4, 2)) + 4; - var decBitNumber = DataConvert.BinToDec(intBitAndDecBitNumberBin.Substring(6, 2)) + 1; - index += 1; - - // hexDatas.GetRange() - var collectorAddressHexList = hexDatas.Skip(index).Take(6).ToList(); - collectorAddressHexList.Reverse(); - var collectorAddress = string.Join("", collectorAddressHexList); - index += 6; - - var userClassNumberBin = DataConvert.HexToBin(hexDatas[index]).PadLeft(8, '0'); - var userClass = DataConvert.BinToDec(userClassNumberBin.Substring(0, 4)); - var userSubClass = DataConvert.BinToDec(userClassNumberBin.Substring(4, 4)); - index += 1; - - meterList.Add(new MeterParameter() - { - Pn = pn, - BaudRate = baudRate, - Port = port, - ProtocolType = protocolType, - Address = address, - Password = password, - RateNumber = rateNumber, - IntegerBitNumber = intBitNumber, - DecimalBitNumber = decBitNumber, - CollectorAddress = collectorAddress, - UserCategoryNumber = userClass, - UserSubclassNumber = userSubClass, - }); - } - return meterList; - } - - /// - /// 解析实时数据F129 - /// - /// - private void AnalysisAFN0CF129DataUnit(List hexDatas) - { - var minutes = Convert.ToInt32(hexDatas[0]); // 获取当前分钟数 - var hours = Convert.ToInt32(hexDatas[1]); // 获取当前小时数 - var day = Convert.ToInt32(hexDatas[2]); // 获取当前日期的日数 - var month = Convert.ToInt32(hexDatas[3]); // 获取当前月份 - var year = Convert.ToInt32(hexDatas[4]); // 获取当前日期的年份 - - var rateNumber = Convert.ToInt32(hexDatas[5]); - var kwhTotal = hexDatas.Skip(5).Take(5).ToList(); - var kwhList = new List(); - var index = 11; - for (int i = 0; i < rateNumber; i++) - { - var kwhHexList = hexDatas.Skip(11).Take(5).ToList(); - kwhHexList.Reverse(); - var integerStr = $"{kwhHexList.Take(0)}{kwhHexList.Take(1)}{kwhHexList.Take(2)}"; - var decimalValStr = $"{kwhHexList[3]}{kwhHexList[4]}"; - var val = decimal.Parse($"{integerStr}{decimalValStr}"); - kwhList.Add(val); - index += 5; - } - } - #endregion - - #region 下行命令 - - /// - /// 设置电表档案 - /// - /// 集中器地址 - /// - public void GetSetAmmeterParameter(string a, List meterParameters) - { - var dataUnit = GetAFN04F10DataUnit(meterParameters); - var bytes = GetCommandBytes(new ReqParameter2() - { - AFN = AFN.设置参数, - FunCode = (int)CMasterStationFunCode.请求1级数据, - A = a, - Seq = new Seq() - { - TpV = TpV.附加信息域中无时间标签, - FIRFIN = FIRFIN.单帧, - CON = CON.需要对该帧进行确认, - PRSEQ = 10, - }, - MSA = GetMSA(a), - Pn = 0, - Fn = 10 - }, dataUnit); - } - - /// - /// 查询电表档案 - /// - /// - /// 对象序号 - public void GetAmmeterParameter(string a, List meterNumberList) - { - var dataUnit = new List(); - var countHex = DataConvert.DecToHex(meterNumberList.Count()).PadLeft(4, '0'); - var countHexPairs = DataConvert.StringToPairs(countHex); - countHexPairs.Reverse(); - dataUnit.AddRange(countHexPairs); - - foreach (var number in meterNumberList) - { - var numberHex = DataConvert.DecToHex(number).PadLeft(4, '0'); - var numberHexPairs = DataConvert.StringToPairs(numberHex); - numberHexPairs.Reverse(); - dataUnit.AddRange(numberHexPairs); - } - var bytes = GetCommandBytes(new ReqParameter2() - { - AFN = AFN.查询参数, - FunCode = (int)CMasterStationFunCode.请求2级数据, - A = a, - Seq = new Seq() - { - TpV = TpV.附加信息域中无时间标签, - FIRFIN = FIRFIN.单帧, - CON = CON.不需要对该帧进行确认, - PRSEQ = 0, - }, - MSA = GetMSA(a), - Pn = 0, - Fn = 10 - }, dataUnit); - } - - /// - /// 电表抄读 - /// - /// - /// - public void GetAmmterReading(string a, int pn) - { - var bytes = GetCommandBytes(new ReqParameter2() - { - AFN = AFN.请求实时数据, - FunCode = (int)CMasterStationFunCode.请求2级数据, - A = a, - Seq = new Seq() - { - TpV = TpV.附加信息域中无时间标签, - FIRFIN = FIRFIN.单帧, - CON = CON.不需要对该帧进行确认, - PRSEQ = 2, - }, - MSA = GetMSA(a), - Pn = pn, - Fn = 129 - }); - } - - /// - /// 组装电表阀控 - /// - /// 电表地址 - /// 特殊控制码 - /// 密码 - /// 是否为开阀 - /// - public List AmmeterValveControl(string address, string specialnocode, string password, bool state, string modelCode = "") - { - address = address.Trim().TrimStart('0'); - if (address.Length < 12) address = address.PadLeft(12, '0'); - string Code = string.Empty; - - if (state) - { - if (string.IsNullOrEmpty(specialnocode)) - Code = "1B"; - else - Code = specialnocode == "1B" || specialnocode == "1C" ? specialnocode : "1C"; - } - else - Code = "1A";//跳闸 - - if (specialnocode == "1W") - { - if (state) - Code = "1A"; - else - Code = "1C"; - } - - var pwdLevel = "02"; - if (modelCode == "HL_DTSU2625" || modelCode == "DDZY9866") - pwdLevel = "04"; - else if (modelCode == "DDS2705") - pwdLevel = "03"; - - if (!string.IsNullOrWhiteSpace(password) && password.Contains("|")) - { - var sp = password.Split('|'); - pwdLevel = sp[1]; - password = sp[0]; - } - - string strDate = DataConvert.StrAddSpan(DateTime.Now.AddYears(3).ToString("000012ddMMyy")); - if (specialnocode == "1D" || modelCode == "SZBD_DDZY1225") - strDate = "FF FF FF FF FF FF"; - string strP = DataConvert.StrReverseOrder(DataConvert.StrAddSpan(password)); - string strSJY = " " + pwdLevel + " " + strP + " 01 00 00 00 " + Code + " 00 " + strDate; - string strLen = (strSJY.Replace(" ", "").Length / 2).ToString("X2"); - string strReturn = "68 " + DataConvert.StrReverseOrder(DataConvert.StrAddSpan(address)) + " 68 1C " + strLen + " " + DataConvert.StrAddHex33(strSJY) + " "; - string strSum = strReturn.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).Select(i => Convert.ToInt32(i, 16)).Sum().ToString("X"); - strReturn += strSum.Substring(strSum.Length - 2) + " 16"; - - return strReturn.Split(' ').ToList(); - } - - /// - /// 帧命令组装 - /// - /// 请求参数 - /// 数据单元 - /// - public byte[] GetCommandBytes(ReqParameter reqParameter, List? dataUnit = null) - { - var cmdStrList = new List(); - var userDatas = GetUserData(reqParameter, dataUnit); - var hearders = GetHeaders(userDatas.Count); - var cs = GetCS(userDatas); - cmdStrList.AddRange(hearders); - cmdStrList.AddRange(userDatas); - cmdStrList.Add(cs); - cmdStrList.Add(end); - Console.WriteLine($"回复:{string.Join(" ", cmdStrList)}"); - var bytes = cmdStrList.Select(x => Convert.ToByte(x, 16)).ToArray(); - return bytes; - } - - - /// - /// 固定长度的报文头 起始字符+长度+长度+起始字符 - /// - /// - /// - private List GetHeaders(int length) - { - var headers = new List(); - headers.Add(stx); - var l = GetLength(length); - headers.AddRange(l); - headers.AddRange(l); - headers.Add(stx); - return headers; - } - - /// - /// 用户数据区 - /// - /// - /// - public List GetUserData(ReqParameter reqParameter, List? dataUnit) - { - var c = GetC(reqParameter.FunCode, reqParameter.PRM); - var a = GetAList(reqParameter.A, reqParameter.MSA); - - var linkUserData = GetLinkUserData(reqParameter.AFN, reqParameter.Seq, - ((ReqParameter2)reqParameter).Pn, ((ReqParameter2)reqParameter).Fn, dataUnit); - - var list = new List() { c }; - list.AddRange(a); - list.AddRange(linkUserData); - return list; - } - - - /// - /// 长度 2字节 [用户数据区长度] - /// - /// - private List GetLength(int length1) - { - var binaryLen = DataConvert.DecToBin(length1); - var protocolIdentification = Enum.Format(typeof(ProtocolIdentification), - ProtocolIdentification.本规约使用, "d").PadLeft(2, '0'); - var lenStr = $"{binaryLen}{protocolIdentification}"; - var hexLen = DataConvert.BinToHex(lenStr); - hexLen = hexLen.PadLeft(4, '0'); - var list = DataConvert.StringToPairs(hexLen); - list.Reverse(); - return list; - } - - /// - /// 控制域 - /// - /// 功能码 - /// - /// - /// - private string GetC(int funCode, PRM pRM, int fcb = 0, FCV fcv = FCV.FCB位无效) - { - var cMasterStationFunCodeHex = DataConvert.DecToBin(funCode); - cMasterStationFunCodeHex = cMasterStationFunCodeHex.ToString().PadLeft(4, '0'); - var strC = $"{(int)DIR.主站下行报文}{(int)pRM}{fcb}{(int)fcv}{cMasterStationFunCodeHex}"; - var hexC = DataConvert.BinToHex(strC).PadLeft(2, '0'); - return hexC; - } - - /// - /// 地址域 3220 09872 - /// - /// 行政区划码 BCD码 3220=2032 - /// 逻辑地址 BIN 09872=2690=>9026 - /// 主站地址 BIN 0~127 - /// - private List GetAList(string a, int mSA) - { - var list = new List(); - - var a1 = a.Substring(0, 4); - var a1Pairs = DataConvert.StringToPairs(a1); - a1Pairs.Reverse(); - list.AddRange(a1Pairs); - - var a2 = Convert.ToInt32(a.Substring(4)); - var decA2 = DataConvert.DecToHex(a2); - var a2Pairs = DataConvert.StringToPairs(decA2.PadLeft(4, '0')); - a2Pairs.Reverse(); - list.AddRange(a2Pairs); - - //TODO:主站地址和组地址标志 - var a3Bin = $"{DataConvert.DecToBin(mSA).PadLeft(7, '0')}0"; - list.Add(DataConvert.BinToHex(a3Bin).PadLeft(2, '0')); - - return list; - } - - #region 链路用户数据 - - private List GetLinkUserData(AFN aFN, Seq seq, int pn, int fn, List? dataUnit) - { - var aFNValue = DataConvert.DecToHex((int)aFN).PadLeft(2, '0'); - var sEQ = GetSEQ(seq.TpV, seq.FIRFIN, seq.CON, seq.PRSEQ); - var dA = GetDA(pn); - var dT = GetDT(fn); - var list = new List() { aFNValue, sEQ }; - list.AddRange(dA); - list.AddRange(dT); - - if (dataUnit != null) - { - list.AddRange(dataUnit); - } - //list.AddRange(GetDataUnit(aFN,seq)); - - if (seq.TpV == TpV.附加信息域中带时间标签) - list.AddRange(GetTp("00")); - - return list; - } - - - /// - /// 帧序列域 - /// - /// - /// - /// - /// - private string GetSEQ(TpV tpV, FIRFIN fIRFIN, CON cON, int pRSEQ) - { - var tpVValue = Enum.Format(typeof(TpV), - tpV, "d"); - var fIRFINValue = Enum.Format(typeof(FIRFIN), - fIRFIN, "d"); - var cONValue = (int)cON; - var sEQBin = $"{tpVValue}{fIRFINValue}{cONValue}{DataConvert.DecToBin(pRSEQ).PadLeft(4, '0')}"; - var hexSEQ = DataConvert.BinToHex(sEQBin).PadLeft(2, '0'); - return hexSEQ; - } - - /// - /// 信息点标识 - /// - /// 计量点 - /// - private List GetDA(int pn) - { - if (pn == 0) - return new List() { "00", "00" }; - var dA2 = (pn - 1) / 8 + 1;//信息点组从1开始 第几组 - var dA1 = pn - (dA2 - 1) * 8;//pn % 8 - var dA1Hex = DataConvert.BinToHex("1".PadRight(dA1, '0'));//对位信息 第几位 二进制有效位 - var dA2Hex = DataConvert.DecToHex(dA2); - return new List() { dA1Hex.PadLeft(2, '0'), dA2Hex.PadLeft(2, '0') }; - - } - - /// - /// 数据单元标识 - /// - /// - /// - private List GetDT(int fn) - { - var dT2 = (fn - 1) / 8;//从零开始 第几组 - var dT1 = fn - dT2 * 8; - var dT1Hex = DataConvert.BinToHex("1".PadRight(dT1, '0'));//对位信息 第几位 二进制有效位 - var dT2Hex = DataConvert.DecToHex(dT2); - return new List() { dT1Hex.PadLeft(2, '0'), dT2Hex.PadLeft(2, '0') }; - } - - private List GetDataUnit(AFN aFN, Seq seq) - { - var datas = new List(); - switch (aFN) - { - case AFN.确认或否认: - break; - case AFN.复位: - break; - case AFN.链路接口检测: - break; - case AFN.中继站命令: - break; - case AFN.设置参数: - break; - case AFN.控制命令: - break; - case AFN.身份认证及密钥协商: - break; - case AFN.备用: - break; - case AFN.请求被级联终端主动上报: - break; - case AFN.请求终端配置: - break; - case AFN.查询参数: - break; - case AFN.请求任务数据: - break; - case AFN.请求实时数据: - break; - case AFN.请求历史数据: - break; - case AFN.请求事件数据: - break; - case AFN.文件传输: - break; - case AFN.数据转发: - break; - default: - break; - } - if (seq.TpV == TpV.附加信息域中带时间标签) - datas.AddRange(GetTp("00")); - return datas; - } - - private void GetAFN00DataUnit(Seq seq) - { - //EC+Tp - - } - - /// - /// 终端电能表配置参数 - /// - /// - /// - public List GetAFN04F10DataUnit(List meterParameters) - { - var hexDatas = new List(); - - var countHex = DataConvert.DecToHex(meterParameters.Count()).PadLeft(4, '0'); - hexDatas.Add(countHex); - - //TODO 优化代码:目标数据入参,返回类型为出参 - for (int i = 0; i <= meterParameters.Count - 1; i++) - { - var meter = meterParameters[i]; - - var indexHex = DataConvert.DecToHex(i + 1).PadLeft(4, '0'); - hexDatas.Add(indexHex); - - var pnHex = DataConvert.DecToHex(meter.Pn).PadLeft(4, '0'); - hexDatas.Add(pnHex); - - var baudRateBin = DataConvert.DecToBin(meter.BaudRate).PadLeft(3, '0'); - var portBin = DataConvert.DecToBin(meter.Port).PadLeft(5, '0'); - var baudRateAndPortHex = DataConvert.BinToHex($"{baudRateBin}{portBin}").PadLeft(2, '0'); - hexDatas.Add(baudRateAndPortHex); - - var protocolTypeHex = DataConvert.DecToHex((int)meter.ProtocolType).PadLeft(2, '0'); - hexDatas.Add(protocolTypeHex); - - hexDatas.Add(meter.Address); - - hexDatas.Add(meter.Password.PadLeft(12, '0')); - - var rateNumberBin = $"0000{DataConvert.DecToBin(meter.RateNumber).PadLeft(4, '0')}"; - var rateNumberHex = DataConvert.BinToHex(rateNumberBin).PadLeft(2, '0'); - hexDatas.Add(rateNumberHex); - - var intBitNumberBin = DataConvert.DecToBin(meter.IntegerBitNumber - 4).PadLeft(2, '0'); - var decBitNumberBin = DataConvert.DecToBin(meter.DecimalBitNumber - 1).PadLeft(2, '0'); - var intAndDecBitNumberBin = $"0000{intBitNumberBin}{decBitNumberBin}"; - var intAndDecBitNumberHex = DataConvert.BinToHex(intAndDecBitNumberBin).PadLeft(2, '0'); - hexDatas.Add(intAndDecBitNumberHex); - - hexDatas.Add(meter.CollectorAddress.PadLeft(12, '0')); - - var userCategoryNumberBin = DataConvert.DecToBin(meter.UserCategoryNumber).PadLeft(4, '0'); - var userSubclassNumberBin = DataConvert.DecToBin(meter.UserSubclassNumber).PadLeft(4, '0'); - var userNumberHex = DataConvert.BinToHex($"{userCategoryNumberBin}{userSubclassNumberBin}").PadLeft(2, '0'); - hexDatas.Add(userNumberHex); - } - - //高位在前,低位在后 - var datas = new List(); - foreach (var hexData in hexDatas) - { - if (hexData.Length == 2) - datas.Add(hexData); - else - { - var lst = DataConvert.StringToPairs(hexData); - lst.Reverse(); - datas.AddRange(lst); - } - } - datas.AddRange(GetPW()); - return datas; - } - - /// - /// 透明转发 - /// - /// 终端通信端口 1~31 - /// 0~7 对应300,600,1200,2400,4800,7200,9600,19200 - /// - /// - /// - /// - public List GetAFN1001DataUnit(int port, BaudRate baudRate, StopBit stopBit, Parity parity, DataBit dataBit, - int waitContentTimeout, int waitByteTimeout, List datas) - { - var dataUnit = new List(); - - var portHex = DataConvert.DecToHex(port).PadLeft(2, '0'); - dataUnit.Add(portHex); - - var baudRateBin = DataConvert.DecToBin((int)baudRate).PadLeft(3, '0'); - var stopBitBin = DataConvert.DecToBin((int)stopBit); - var parityBin = parity != Parity.None ? $"1{DataConvert.DecToBin((int)parity)}" : $"0{DataConvert.DecToBin((int)parity)}"; - var dataBitBin = DataConvert.DecToBin((int)dataBit).PadLeft(2, '0'); - var controlHex = DataConvert.BinToHex($"{baudRateBin}{stopBitBin}{parityBin}{dataBitBin}").PadLeft(2, '0'); ; - dataUnit.Add(controlHex); - - var waitContentTimeoutBin = $"1{DataConvert.DecToBin(waitContentTimeout).PadLeft(7, '0')}"; - var waitContentTimeoutHex = DataConvert.BinToHex(waitContentTimeoutBin).PadLeft(2, '0'); - var waitByteTimeoutHex = DataConvert.DecToHex(waitByteTimeout).PadLeft(2, '0'); - - dataUnit.Add(waitContentTimeoutHex); - dataUnit.Add(waitByteTimeoutHex); - - var countHex = DataConvert.DecToHex(datas.Count).PadLeft(4, '0'); - var countHexPairs = DataConvert.StringToPairs(countHex); - countHexPairs.Reverse(); - dataUnit.AddRange(countHexPairs); - - dataUnit.AddRange(datas); - - return dataUnit; - } - - //TODO AUX=消息认证码字段(PW,16个字节)+时间标签 - private List GetPW() - { - var str = "00"; - var pWList = Enumerable.Repeat(str, pWLen).ToList(); - return pWList; - } - - /// - /// 时间标签 - /// - /// 启动帧帧序号计数器PFC 1字节 - /// 允许发送传输延时时间 min 1字节 - /// - private List GetTp(string pFC = "00", int delayTime = 0) - { - - var now = DateTime.Now; // 获取当前时间 - var seconds = now.Second.ToString().PadLeft(2, '0'); // 获取当前秒数 - var minutes = now.Minute.ToString().PadLeft(2, '0'); // 获取当前分钟数 - var hours = now.Hour.ToString().PadLeft(2, '0'); // 获取当前小时数 - var day = now.Day.ToString().PadLeft(2, '0'); // 获取当前日期的日数 - return new List() { pFC, seconds, minutes, hours, day, delayTime.ToString().PadLeft(2, '0') }; - } - - #endregion - - /// - /// 帧校验和 - /// - /// 用户数据区 - /// - private string GetCS(List userData) - { - byte sum = 0; - foreach (var d in userData) - { - var b = Convert.ToByte(d, 16); - sum += b; - } - return sum.ToString("X2"); - } - - #endregion - - } } diff --git a/JiShe.CollectBus.RabbitMQ/Consumers/MessageIssuedConsumer.cs b/JiShe.CollectBus.RabbitMQ/Consumers/MessageIssuedConsumer.cs index f78e267..744b4a7 100644 --- a/JiShe.CollectBus.RabbitMQ/Consumers/MessageIssuedConsumer.cs +++ b/JiShe.CollectBus.RabbitMQ/Consumers/MessageIssuedConsumer.cs @@ -1,7 +1,5 @@ -using JiShe.CollectBus.Protocol.Contracts.Interfaces; -using JiShe.CollectBus.Protocol.Contracts.Models; +using JiShe.CollectBus.Protocol.Contracts.Models; using MassTransit; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using TouchSocket.Sockets; @@ -15,7 +13,7 @@ namespace JiShe.CollectBus.RabbitMQ.Consumers public MessageIssuedConsumer(ILogger logger, ITcpService tcpService) { _logger = logger; - _tcpService = tcpService; + _tcpService = tcpService; } public async Task Consume(ConsumeContext context) diff --git a/JiShe.CollectBus.RabbitMQ/Consumers/MessageReceivedHeartbeatConsumer.cs b/JiShe.CollectBus.RabbitMQ/Consumers/MessageReceivedHeartbeatConsumer.cs new file mode 100644 index 0000000..ceda2ae --- /dev/null +++ b/JiShe.CollectBus.RabbitMQ/Consumers/MessageReceivedHeartbeatConsumer.cs @@ -0,0 +1,35 @@ +using JiShe.CollectBus.Protocol.Contracts.Interfaces; +using JiShe.CollectBus.Protocol.Contracts.Models; +using MassTransit; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace JiShe.CollectBus.RabbitMQ.Consumers +{ + public class MessageReceivedHeartbeatConsumer : IConsumer + { + private readonly ILogger _logger; + private readonly IServiceProvider _serviceProvider; + + public MessageReceivedHeartbeatConsumer(ILogger logger, IServiceProvider serviceProvider) + { + _logger = logger; + _serviceProvider = serviceProvider; + } + + public async Task Consume(ConsumeContext context) + { + _logger.LogInformation("心跳消费队列开始处理"); + var protocolPlugin = _serviceProvider.GetKeyedService("StandardProtocol"); + if (protocolPlugin == null) + { + _logger.LogError("【心跳消费队列开始处理】协议不存在!"); + } + else + { + await protocolPlugin.HeartbeatAsync(context.Message); + _logger.LogInformation("心跳消费队列完成处理"); + } + } + } +} diff --git a/JiShe.CollectBus.RabbitMQ/Consumers/MessageReceivedLoginConsumer.cs b/JiShe.CollectBus.RabbitMQ/Consumers/MessageReceivedLoginConsumer.cs new file mode 100644 index 0000000..0132baa --- /dev/null +++ b/JiShe.CollectBus.RabbitMQ/Consumers/MessageReceivedLoginConsumer.cs @@ -0,0 +1,35 @@ +using JiShe.CollectBus.Protocol.Contracts.Interfaces; +using JiShe.CollectBus.Protocol.Contracts.Models; +using MassTransit; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace JiShe.CollectBus.RabbitMQ.Consumers +{ + public class MessageReceivedLoginConsumer : IConsumer + { + private readonly ILogger _logger; + private readonly IServiceProvider _serviceProvider; + + public MessageReceivedLoginConsumer(ILogger logger, IServiceProvider serviceProvider) + { + _logger = logger; + _serviceProvider = serviceProvider; + } + + public async Task Consume(ConsumeContext context) + { + _logger.LogInformation("登录消费队列开始处理"); + var protocolPlugin = _serviceProvider.GetKeyedService("StandardProtocol"); + if (protocolPlugin == null) + { + _logger.LogError("【登录消费队列开始处理】协议不存在!"); + } + else + { + await protocolPlugin.LoginAsync(context.Message); + _logger.LogInformation("登录消费队列完成处理"); + } + } + } +} diff --git a/JiShe.CollectBus.RabbitMQ/JiSheCollectBusRabbitMqModule.cs b/JiShe.CollectBus.RabbitMQ/JiSheCollectBusRabbitMqModule.cs index eaeed17..7b9db9f 100644 --- a/JiShe.CollectBus.RabbitMQ/JiSheCollectBusRabbitMqModule.cs +++ b/JiShe.CollectBus.RabbitMQ/JiSheCollectBusRabbitMqModule.cs @@ -1,10 +1,8 @@ -using System; -using JiShe.CollectBus.Common.Interfaces; +using JiShe.CollectBus.Common.Interfaces; using JiShe.CollectBus.RabbitMQ.Consumers; using MassTransit; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using RabbitMQ.Client; namespace JiShe.CollectBus.RabbitMQ { @@ -17,6 +15,8 @@ namespace JiShe.CollectBus.RabbitMQ { x.AddConsumer(); x.AddConsumer(); + x.AddConsumer(); + x.AddConsumer(); x.UsingRabbitMq((context, cfg) => { cfg.Host(configuration["MQ:Host"], ushort.Parse(configuration["MQ:Port"] ?? string.Empty), configuration["MQ:VirtualHost"], h => @@ -31,7 +31,18 @@ namespace JiShe.CollectBus.RabbitMQ configurator.ConfigureConsumeTopology = false; configurator.Consumer(context); }); - + // 登录 + cfg.ReceiveEndpoint($"{configuration["MQ:Queue:Received"]}_Login" ?? string.Empty, configurator => + { + configurator.ConfigureConsumeTopology = false; + configurator.Consumer(context); + }); + // 心跳 + cfg.ReceiveEndpoint($"{configuration["MQ:Queue:Received"]}_Heartbeat" ?? string.Empty, configurator => + { + configurator.ConfigureConsumeTopology = false; + configurator.Consumer(context); + }); // 消息下发队列 cfg.ReceiveEndpoint(configuration["MQ:Queue:Issued"] ?? string.Empty, configurator => { diff --git a/JiShe.CollectBus.RabbitMQ/Senders/INSender.cs b/JiShe.CollectBus.RabbitMQ/Senders/INSender.cs index 0f5c8fc..52e5a87 100644 --- a/JiShe.CollectBus.RabbitMQ/Senders/INSender.cs +++ b/JiShe.CollectBus.RabbitMQ/Senders/INSender.cs @@ -12,6 +12,10 @@ namespace JiShe.CollectBus.RabbitMQ.Senders Task SendToIssuedAsync(object message, CancellationToken cancellationToken = default); Task SendToReceivedAsync(T message, CancellationToken cancellationToken = default) where T : class; Task SendToReceivedAsync(object message, CancellationToken cancellationToken = default); + Task SendToReceivedLoginAsync(T message, CancellationToken cancellationToken = default) where T : class; + Task SendToReceivedLoginAsync(object message, CancellationToken cancellationToken = default); + Task SendToReceivedHeartbeatAsync(T message, CancellationToken cancellationToken = default) where T : class; + Task SendToReceivedHeartbeatAsync(object message, CancellationToken cancellationToken = default); Task SendAsync(string queueKey, object message, CancellationToken cancellationToken = default); } diff --git a/JiShe.CollectBus.RabbitMQ/Senders/NSender.cs b/JiShe.CollectBus.RabbitMQ/Senders/NSender.cs index 3a57911..b435e4c 100644 --- a/JiShe.CollectBus.RabbitMQ/Senders/NSender.cs +++ b/JiShe.CollectBus.RabbitMQ/Senders/NSender.cs @@ -43,6 +43,26 @@ namespace JiShe.CollectBus.RabbitMQ.Senders await SendAsync(_receivedKey, message, cancellationToken); } + public async Task SendToReceivedLoginAsync(T message, CancellationToken cancellationToken = default) where T : class + { + await SendAsync($"{_receivedKey}_Login", message, cancellationToken); + } + + public async Task SendToReceivedLoginAsync(object message, CancellationToken cancellationToken = default) + { + await SendAsync($"{_receivedKey}_Login", message, cancellationToken); + } + + public async Task SendToReceivedHeartbeatAsync(T message, CancellationToken cancellationToken = default) where T : class + { + await SendAsync($"{_receivedKey}_Heartbeat", message, cancellationToken); + } + + public async Task SendToReceivedHeartbeatAsync(object message, CancellationToken cancellationToken = default) + { + await SendAsync($"{_receivedKey}_Heartbeat", message, cancellationToken); + } + public async Task SendAsync(string queueKey, object message, CancellationToken cancellationToken = default) {