2025-04-27 16:32:03 +08:00
|
|
|
|
using JiShe.CollectBus.Common;
|
2025-06-06 14:15:31 +08:00
|
|
|
|
using JiShe.CollectBus.Common.Enums;
|
2025-04-27 16:32:03 +08:00
|
|
|
|
using JiShe.CollectBus.IotSystems.Ammeters;
|
2025-03-14 14:28:04 +08:00
|
|
|
|
using JiShe.CollectBus.IotSystems.Devices;
|
2025-04-25 14:23:06 +08:00
|
|
|
|
using JiShe.CollectBus.Protocol.Interfaces;
|
|
|
|
|
|
using JiShe.CollectBus.Protocol3761;
|
2024-12-19 16:07:07 +08:00
|
|
|
|
using Microsoft.Extensions.Logging;
|
2025-04-27 16:32:03 +08:00
|
|
|
|
using Microsoft.Extensions.Options;
|
2024-12-19 16:07:07 +08:00
|
|
|
|
using TouchSocket.Core;
|
|
|
|
|
|
using TouchSocket.Sockets;
|
|
|
|
|
|
using Volo.Abp.Caching;
|
|
|
|
|
|
using Volo.Abp.DependencyInjection;
|
|
|
|
|
|
using Volo.Abp.Domain.Repositories;
|
|
|
|
|
|
|
|
|
|
|
|
namespace JiShe.CollectBus.Plugins
|
|
|
|
|
|
{
|
2025-05-18 17:18:31 +08:00
|
|
|
|
public partial class TcpMonitor : PluginBase, ITransientDependency, ITcpReceivedPlugin, ITcpConnectingPlugin, ITcpConnectedPlugin, ITcpClosedPlugin, ITcpClosingPlugin
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
2025-04-15 18:58:38 +08:00
|
|
|
|
private readonly IProducerService _producerService;
|
2024-12-19 16:07:07 +08:00
|
|
|
|
private readonly ILogger<TcpMonitor> _logger;
|
|
|
|
|
|
private readonly IDistributedCache<AmmeterInfo> _ammeterInfoCache;
|
2025-04-21 23:47:11 +08:00
|
|
|
|
private readonly IServiceProvider _serviceProvider;
|
2025-04-23 15:10:20 +08:00
|
|
|
|
private readonly IProtocolService _protocolService;
|
2025-04-27 16:32:03 +08:00
|
|
|
|
private readonly ServerApplicationOptions _serverApplicationOptions;
|
2025-06-06 14:15:31 +08:00
|
|
|
|
private readonly IFreeRedisProvider _freeRedisProvider;
|
2024-12-19 16:07:07 +08:00
|
|
|
|
|
2025-04-23 15:10:20 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
///
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="producerService"></param>
|
|
|
|
|
|
/// <param name="logger"></param>
|
|
|
|
|
|
/// <param name="ammeterInfoCache"></param>
|
|
|
|
|
|
/// <param name="serviceProvider"></param>
|
2025-04-27 16:32:03 +08:00
|
|
|
|
/// <param name="serverApplicationOptions"></param>
|
|
|
|
|
|
/// <param name="protocolService"></param>
|
2025-06-06 14:15:31 +08:00
|
|
|
|
/// <param name="freeRedisProvider"></param>
|
2025-04-18 09:50:00 +08:00
|
|
|
|
public TcpMonitor(IProducerService producerService,
|
2025-03-27 08:38:19 +08:00
|
|
|
|
ILogger<TcpMonitor> logger,
|
2025-04-27 16:32:03 +08:00
|
|
|
|
IDistributedCache<AmmeterInfo> ammeterInfoCache,
|
|
|
|
|
|
IServiceProvider serviceProvider,
|
|
|
|
|
|
IOptions<ServerApplicationOptions> serverApplicationOptions,
|
2025-06-06 14:15:31 +08:00
|
|
|
|
IProtocolService protocolService,
|
|
|
|
|
|
IFreeRedisProvider freeRedisProvider)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
2025-04-15 18:58:38 +08:00
|
|
|
|
_producerService = producerService;
|
2024-12-19 16:07:07 +08:00
|
|
|
|
_logger = logger;
|
|
|
|
|
|
_ammeterInfoCache = ammeterInfoCache;
|
2025-04-21 23:47:11 +08:00
|
|
|
|
_serviceProvider= serviceProvider;
|
2025-04-23 15:10:20 +08:00
|
|
|
|
_protocolService = protocolService;
|
2025-04-27 16:32:03 +08:00
|
|
|
|
_serverApplicationOptions = serverApplicationOptions.Value;
|
2025-06-06 14:15:31 +08:00
|
|
|
|
_freeRedisProvider = freeRedisProvider;
|
2024-12-19 16:07:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-27 08:38:19 +08:00
|
|
|
|
public async Task OnTcpReceived(ITcpSession client, ReceivedDataEventArgs e)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
2025-04-27 16:32:03 +08:00
|
|
|
|
if (string.IsNullOrWhiteSpace(_serverApplicationOptions.DefaultProtocolPlugin))
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"请配置默认的端到云协议插件!");
|
|
|
|
|
|
}
|
2024-12-19 16:07:07 +08:00
|
|
|
|
var messageHexString = Convert.ToHexString(e.ByteBlock.Span);
|
2025-04-27 16:32:03 +08:00
|
|
|
|
var protocolPlugin = await _protocolService.GetProtocolServiceAsync(_serverApplicationOptions.DefaultProtocolPlugin);
|
2025-04-21 23:47:11 +08:00
|
|
|
|
if (protocolPlugin == null)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
2025-04-27 16:32:03 +08:00
|
|
|
|
_logger.LogError($"默认的端到云协议插件{_serverApplicationOptions.DefaultProtocolPlugin}不存在!");
|
2024-12-19 16:07:07 +08:00
|
|
|
|
}
|
2025-04-23 15:10:20 +08:00
|
|
|
|
var tcpSessionClient = (ITcpSessionClient)client;
|
2025-04-27 15:30:45 +08:00
|
|
|
|
|
2025-04-21 23:47:11 +08:00
|
|
|
|
TB3761? tB3761 = await protocolPlugin!.AnalyzeAsync<TB3761>(tcpSessionClient, messageHexString);
|
2025-04-22 09:34:59 +08:00
|
|
|
|
if (tB3761 == null)
|
|
|
|
|
|
{
|
2025-04-25 09:28:56 +08:00
|
|
|
|
// TODO: 暂时不处理,后续再处理
|
2025-04-22 09:34:59 +08:00
|
|
|
|
_logger.LogError($"指令初步解析失败,指令内容:{messageHexString}");
|
|
|
|
|
|
}
|
2025-04-29 11:43:16 +08:00
|
|
|
|
|
2025-06-06 14:15:31 +08:00
|
|
|
|
////登录和心跳的时候,需要过滤TCP连接
|
|
|
|
|
|
//if (tB3761.DT?.Fn == (int)FN.登录 || tB3761.DT?.Fn == (int)FN.心跳)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// string focusAddress = tB3761.A.Code;
|
|
|
|
|
|
// if (string.IsNullOrWhiteSpace(focusAddress))//集中器地址为空,主动关闭连接
|
|
|
|
|
|
// {
|
|
|
|
|
|
// await tcpSessionClient.CloseAsync();
|
|
|
|
|
|
// _logger.LogError($"指令解析失败,没有找到集中器地址,指令内容:{messageHexString}");
|
|
|
|
|
|
// return;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// //查找Redis缓存的集中器信息
|
|
|
|
|
|
// var focusCacheInfos = _freeRedisProvider.Instance.HGet<FocusCacheInfos>(RedisConst.CacheAllFocusInfoHashKey, focusAddress);
|
|
|
|
|
|
// if (focusCacheInfos == null)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// await tcpSessionClient.CloseAsync();
|
|
|
|
|
|
// _logger.LogError($"TCP连接关闭,没有找到集中器地址{focusAddress}的缓存信息");
|
|
|
|
|
|
// return;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// //检查集中器的信息的服务器标记是否为空,如果不为空,需要检查是否与当前服务器的标记一致
|
|
|
|
|
|
// if (!string.IsNullOrWhiteSpace(focusCacheInfos.ServerTagName) && focusCacheInfos.ServerTagName != _serverApplicationOptions.ServerTagName)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// await tcpSessionClient.CloseAsync();
|
|
|
|
|
|
// _logger.LogError($"TCP连接关闭,集中器地址{focusAddress}的服务器标记为:{focusCacheInfos.ServerTagName},当前服务器的标记为:{_serverApplicationOptions.ServerTagName},不一致拒绝连接。");
|
|
|
|
|
|
// return;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// int currentTCPConnectionCount = tcpSessionClient.Service.Count;
|
|
|
|
|
|
// int configTCPConnectionCount = _serverApplicationOptions.TCPConnectionCount;//配置TCP连接数量
|
|
|
|
|
|
|
|
|
|
|
|
// _logger.LogWarning($"当前配置连接数量为:{configTCPConnectionCount},当前连接数量为:{currentTCPConnectionCount}");
|
|
|
|
|
|
|
|
|
|
|
|
// if (currentTCPConnectionCount >= configTCPConnectionCount)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// _logger.LogError($"当前连接数量为:{currentTCPConnectionCount},大于配置连接数量{configTCPConnectionCount},将拒绝集中{focusAddress}连接");
|
|
|
|
|
|
// await tcpSessionClient.CloseAsync();
|
|
|
|
|
|
// return;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// //缓存更新状态
|
|
|
|
|
|
// focusCacheInfos.LastSurvivalTime = DateTime.Now;
|
|
|
|
|
|
// focusCacheInfos.ServerTagName = _serverApplicationOptions.ServerTagName;
|
|
|
|
|
|
// focusCacheInfos.OnLineStatus = true;
|
|
|
|
|
|
|
|
|
|
|
|
// _freeRedisProvider.Instance.HSet<FocusCacheInfos>(RedisConst.CacheAllFocusInfoHashKey, focusAddress, focusCacheInfos);
|
|
|
|
|
|
|
|
|
|
|
|
// //连接成功以后,通知信息到后台
|
|
|
|
|
|
// Dictionary<ServiceCommunicationTypeEnum, string> channelMessage = new Dictionary<ServiceCommunicationTypeEnum, string>();
|
|
|
|
|
|
// channelMessage.Add(ServiceCommunicationTypeEnum.FocusStatusReceived, focusCacheInfos.Serialize());
|
|
|
|
|
|
// _= _producerService.ProduceAsync(KafkaTopicConsts.ServiceCommunicationChannelTopic, channelMessage);
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
//todo 后续可以考虑Redis的bitmap做日活签到。
|
|
|
|
|
|
|
2025-04-29 11:43:16 +08:00
|
|
|
|
// TODO:要注意保存树模型的时时标字段,如果没有时标,则取接受时间做兼容
|
2025-04-25 09:28:56 +08:00
|
|
|
|
await e.InvokeNext();
|
2024-12-19 16:07:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-27 15:30:45 +08:00
|
|
|
|
|
2025-03-27 08:38:19 +08:00
|
|
|
|
public async Task OnTcpConnecting(ITcpSession client, ConnectingEventArgs e)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
2025-03-27 08:38:19 +08:00
|
|
|
|
var tcpSessionClient = (ITcpSessionClient)client;
|
2025-04-27 15:30:45 +08:00
|
|
|
|
|
2025-03-27 08:38:19 +08:00
|
|
|
|
_logger.LogInformation($"[TCP] ID:{tcpSessionClient.Id} IP:{client.GetIPPort()}正在连接中...");
|
2024-12-19 16:07:07 +08:00
|
|
|
|
await e.InvokeNext();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-27 08:38:19 +08:00
|
|
|
|
public async Task OnTcpConnected(ITcpSession client, ConnectedEventArgs e)
|
2024-12-19 16:07:07 +08:00
|
|
|
|
{
|
2025-03-27 08:38:19 +08:00
|
|
|
|
var tcpSessionClient = (ITcpSessionClient)client;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation($"[TCP] ID:{tcpSessionClient.Id} IP:{client.GetIPPort()}已连接");
|
2024-12-19 16:07:07 +08:00
|
|
|
|
await e.InvokeNext();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-27 08:38:19 +08:00
|
|
|
|
public async Task OnTcpClosed(ITcpSession client, ClosedEventArgs e)
|
2025-06-06 14:15:31 +08:00
|
|
|
|
{
|
|
|
|
|
|
var tcpSessionClient = (ITcpSessionClient)client;
|
2025-05-08 11:25:08 +08:00
|
|
|
|
_logger.LogWarning($"[TCP] ID:{tcpSessionClient.Id} IP:{client.GetIPPort()}已关闭连接");
|
2024-12-19 16:07:07 +08:00
|
|
|
|
|
2025-06-06 14:15:31 +08:00
|
|
|
|
//查找Redis缓存的集中器信息
|
|
|
|
|
|
var focusCacheInfos = _freeRedisProvider.Instance.HGet<FocusCacheInfos>(RedisConst.CacheAllFocusInfoHashKey, tcpSessionClient.Id);
|
|
|
|
|
|
if (focusCacheInfos != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
//缓存更新状态
|
|
|
|
|
|
focusCacheInfos.LastSurvivalTime = DateTime.Now;
|
|
|
|
|
|
focusCacheInfos.ServerTagName = _serverApplicationOptions.ServerTagName;
|
|
|
|
|
|
focusCacheInfos.OnLineStatus = false;
|
|
|
|
|
|
|
|
|
|
|
|
_freeRedisProvider.Instance.HSet<FocusCacheInfos>(RedisConst.CacheAllFocusInfoHashKey, tcpSessionClient.Id, focusCacheInfos);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-19 16:07:07 +08:00
|
|
|
|
await e.InvokeNext();
|
|
|
|
|
|
}
|
2025-03-12 09:58:37 +08:00
|
|
|
|
|
2025-05-18 17:18:31 +08:00
|
|
|
|
public Task OnTcpClosing(ITcpSession client, ClosingEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
var tcpSessionClient = (ITcpSessionClient)client;
|
|
|
|
|
|
_logger.LogWarning($"[TCP] ID:{tcpSessionClient.Id} IP:{client.GetIPPort()}终端主动关闭");
|
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
|
}
|
2024-12-19 16:07:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|