diff --git a/Services/MqttBackgroundService.cs b/Services/MqttBackgroundService.cs index 330d1df..c143430 100644 --- a/Services/MqttBackgroundService.cs +++ b/Services/MqttBackgroundService.cs @@ -1,18 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; +using System.Text; using MQTTnet; using MQTTnet.Client; using MQTTnet.Client.Connecting; using MQTTnet.Client.Disconnecting; using MQTTnet.Client.Options; -using PMSWPF.Models; -using PMSWPF.Services; using PMSWPF.Helper; -using PMSWPF.Enums; +using PMSWPF.Models; namespace PMSWPF.Services { @@ -69,7 +62,7 @@ namespace PMSWPF.Services _serviceMainThread.Start(); } - private void Execute() + private async void Execute() { while (!_stopEvent.WaitOne(0)) { @@ -81,11 +74,23 @@ namespace PMSWPF.Services _reloadEvent.WaitOne(); - // 初始加载MQTT配置和变量数据。 - LoadMqttConfigurations(); - ConnectMqttList(); - - _reloadEvent.Reset(); + try + { + // 初始加载MQTT配置和变量数据。 + var isLoaded = LoadMqttConfigurations(); + if (isLoaded) + { + await ConnectMqttList(); + } + } + catch (Exception e) + { + NotificationHelper.ShowError($"Mqt后台服务主程序在加载变量和连接服务器过程中出现了错误:{e.Message} ", e); + } + finally + { + _reloadEvent.Reset(); + } } } @@ -93,7 +98,7 @@ namespace PMSWPF.Services /// /// 停止MQTT后台服务。 /// - public void StopService() + public async Task StopService() { NlogHelper.Info("Mqtt后台服务开始停止...."); // 记录服务停止信息 @@ -101,7 +106,7 @@ namespace PMSWPF.Services // 取消订阅事件。 _dataServices.OnMqttListChanged -= HandleMqttListChanged; - DisconnecetAll(); + await DisconnecetAll(); // 清空所有字典。 _mqttClients.Clear(); @@ -110,19 +115,24 @@ namespace PMSWPF.Services NlogHelper.Info("Mqtt后台服务已停止。"); // 记录服务停止信息 } - private void DisconnecetAll() + private async Task DisconnecetAll() { // 断开所有已连接的MQTT客户端。 foreach (var mqttId in _mqttClients.Keys.ToList()) { - var client = _mqttClients[mqttId]; - var mqtt = _mqttConfigDic[mqttId]; - mqtt.IsConnected = false; - if (client.IsConnected) + try { - client.DisconnectAsync() - .GetAwaiter() - .GetResult(); + var client = _mqttClients[mqttId]; + var mqtt = _mqttConfigDic[mqttId]; + mqtt.IsConnected = false; + if (client.IsConnected) + { + await client.DisconnectAsync(); + } + } + catch (Exception e) + { + NlogHelper.Error($"MqttID:{mqttId},断开连接的过程中发生了错误:{e.Message}",e); } } } @@ -132,21 +142,30 @@ namespace PMSWPF.Services /// 加载并连接MQTT配置。 /// /// 表示异步操作的任务。 - private void LoadMqttConfigurations() + private bool LoadMqttConfigurations() { - NlogHelper.Info("开始加载Mqtt配置文件..."); - _mqttConfigDic.Clear(); - // 从数据服务获取所有MQTT配置。 - var _mqttConfigList = _dataServices.Mqtts.Where(m => m.IsActive) - .ToList(); - foreach (var mqtt in _mqttConfigList) + try { - mqtt.OnMqttIsActiveChanged += OnMqttIsActiveChangedHandler; - _mqttConfigDic[mqtt.Id] = mqtt; - mqtt.ConnectMessage = "配置加载成功."; - } + NlogHelper.Info("开始加载Mqtt配置文件..."); + _mqttConfigDic.Clear(); + // 从数据服务获取所有MQTT配置。 + var _mqttConfigList = _dataServices.Mqtts.Where(m => m.IsActive) + .ToList(); + foreach (var mqtt in _mqttConfigList) + { + mqtt.OnMqttIsActiveChanged += OnMqttIsActiveChangedHandler; + _mqttConfigDic[mqtt.Id] = mqtt; + mqtt.ConnectMessage = "配置加载成功."; + } - NlogHelper.Info($"Mqtt配置文件加载成功,开启的Mqtt客户端:{_mqttConfigList.Count}个。"); + NlogHelper.Info($"Mqtt配置文件加载成功,开启的Mqtt客户端:{_mqttConfigList.Count}个。"); + return true; + } + catch (Exception e) + { + NotificationHelper.ShowError($"Mqtt后台服务在加载变量的过程中发生了错误:{e.Message}"); + return false; + } } private async void OnMqttIsActiveChangedHandler(Mqtt mqtt) @@ -159,7 +178,7 @@ namespace PMSWPF.Services } else { - if (!_mqttClients.TryGetValue(mqtt.Id,out var client)) + if (!_mqttClients.TryGetValue(mqtt.Id, out var client)) { NlogHelper.Warn($"没有在Mqtt连接字典中找到名字为:{mqtt.Name}的连接。"); return; @@ -167,7 +186,7 @@ namespace PMSWPF.Services if (client.IsConnected) { - await client.DisconnectAsync(); + await client.DisconnectAsync(); } mqtt.IsConnected = false; @@ -175,14 +194,12 @@ namespace PMSWPF.Services _mqttClients.Remove(mqtt.Id); NlogHelper.Info($"{mqtt.Name}的客户端,与服务器断开连接."); - } } catch (Exception e) { - NotificationHelper.ShowError($"{mqtt.Name}客户端,开启或关闭的过程中发生了错误:{e.Message}",e); + NotificationHelper.ShowError($"{mqtt.Name}客户端,开启或关闭的过程中发生了错误:{e.Message}", e); } - } /// @@ -204,7 +221,7 @@ namespace PMSWPF.Services continue; } - await ConnectMqtt(mqtt); + await ConnectMqtt(mqtt); } catch (Exception ex) { @@ -235,11 +252,11 @@ namespace PMSWPF.Services client.UseApplicationMessageReceivedHandler(e => { HandleMessageReceived(e, mqtt); }); // 设置断开连接事件处理程序。 - client.UseDisconnectedHandler(async (e) => await HandleDisconnected(e,options, client, mqtt)); + client.UseDisconnectedHandler(async (e) => await HandleDisconnected(e, options, client, mqtt)); // 尝试连接到MQTT代理。 - await client.ConnectAsync(options, CancellationToken.None); - + await client.ConnectAsync(options, CancellationToken.None); + // 将连接成功的客户端添加到字典。 _mqttClients[mqtt.Id] = client; } @@ -247,7 +264,7 @@ namespace PMSWPF.Services private static void HandleMessageReceived(MqttApplicationMessageReceivedEventArgs e, Mqtt mqtt) { var topic = e.ApplicationMessage.Topic; - var payload = System.Text.Encoding.UTF8.GetString(e.ApplicationMessage.Payload); + var payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload); NlogHelper.Info($"MQTT客户端 {mqtt.Name} 收到消息: 主题={topic}, 消息={payload}"); // 在这里添加处理消息的逻辑 diff --git a/Services/S7BackgroundService.cs b/Services/S7BackgroundService.cs index b410c3b..99dc928 100644 --- a/Services/S7BackgroundService.cs +++ b/Services/S7BackgroundService.cs @@ -1,17 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using S7.Net; -using PMSWPF.Models; using PMSWPF.Enums; using PMSWPF.Helper; +using PMSWPF.Models; +using S7.Net; using S7.Net.Types; -using SqlSugar; using DateTime = System.DateTime; namespace PMSWPF.Services @@ -39,6 +30,8 @@ namespace PMSWPF.Services private readonly int S7PollOnceReadMultipleVars = 9; // S7轮询一遍后的等待时间 private readonly int S7PollOnceSleepTimeMs = 100; + + Dictionary _readVariableDic; // 轮询数据的线程。 private Thread _pollingThread; @@ -62,6 +55,7 @@ namespace PMSWPF.Services _pollVariableDic = new(); _s7PlcClientDic = new(); _variableDic = new(); + _readVariableDic = new(); // 订阅设备列表变更事件,以便在设备配置更新时重新加载。 _dataServices.OnDeviceListChanged += HandleDeviceListChanged; } @@ -116,6 +110,11 @@ namespace PMSWPF.Services _reloadEvent.Reset(); } } + catch (ThreadInterruptedException tie) + { + NlogHelper.Error($"S7后台服务主线程关闭。"); + DisconnectAllPlc(); + } catch (Exception e) { NlogHelper.Error($"S7后台服务主线程运行中发生了错误:{e.Message}",e); @@ -134,7 +133,6 @@ namespace PMSWPF.Services try { // Stopwatch sw = Stopwatch.StartNew(); - int varCount = 0; // 遍历并读取每个S7变量。 foreach (var deviceId in _pollVariableDic.Keys.ToList()) { @@ -163,7 +161,7 @@ namespace PMSWPF.Services continue; } - Dictionary readVarDic = new Dictionary(); + foreach (var variable in variableList) { @@ -178,38 +176,7 @@ namespace PMSWPF.Services if ((DateTime.Now - variable.UpdateTime) < interval) continue; // 未到轮询时间,跳过。 - try - { - readVarDic.Add(variable.Id, DataItem.FromAddress(variable.S7Address)); - varCount++; - if (readVarDic.Count == S7PollOnceReadMultipleVars) - { - // 批量读取 - plcClient.ReadMultipleVars(readVarDic.Values.ToList()); - // 批量读取后还原结果 - foreach (var varId in readVarDic.Keys.ToList()) - { - DataItem dataItem = readVarDic[varId]; - if (!_variableDic.TryGetValue(varId, out var variableData)) - { - NlogHelper.Warn($"S7后台服务批量读取变量后,还原值,在_variableDic中找不到ID为{varId}的变量"); - continue; - } - - // 更新变量的原始数据值和显示值。 - variableData.DataValue = dataItem.Value.ToString(); - variableData.UpdateTime = DateTime.Now; - Console.WriteLine($"S7轮询变量:{variableData.Name},值:{variableData.DataValue}"); - } - - readVarDic.Clear(); - } - - } - catch (Exception ex) - { - NlogHelper.Warn($"从设备 {device.Name} 读取变量 {variable.Name} 失败:{ex.Message}"); - } + ReadVariableData(variable, plcClient, device); } } @@ -225,6 +192,11 @@ namespace PMSWPF.Services NlogHelper.Info("S7后台服务轮询变量结束。"); } + catch (ThreadInterruptedException tie) + { + NlogHelper.Error($"S7后台服务轮询变量线程关闭。"); + DisconnectAllPlc(); + } catch (Exception e) { NlogHelper.Error($"S7后台服务轮询变量线程运行中发生了错误:{e.Message}",e); @@ -232,6 +204,48 @@ namespace PMSWPF.Services } } + /// + /// 读取变量数据 + /// + /// + /// + /// + private void ReadVariableData(VariableData variable, + Plc plcClient, Device device) + { + try + { + _readVariableDic.Add(variable.Id, DataItem.FromAddress(variable.S7Address)); + if (_readVariableDic.Count == S7PollOnceReadMultipleVars) + { + // 批量读取 + plcClient.ReadMultipleVars(_readVariableDic.Values.ToList()); + // 批量读取后还原结果 + foreach (var varId in _readVariableDic.Keys.ToList()) + { + DataItem dataItem = _readVariableDic[varId]; + if (!_variableDic.TryGetValue(varId, out var variableData)) + { + NlogHelper.Warn($"S7后台服务批量读取变量后,还原值,在_variableDic中找不到ID为{varId}的变量"); + continue; + } + // 更新变量的原始数据值和显示值。 + variableData.DataValue = dataItem.Value.ToString(); + variableData.UpdateTime = DateTime.Now; + Console.WriteLine($"S7轮询变量:{variableData.Name},值:{variableData.DataValue}"); + } + + _readVariableDic.Clear(); + } + + } + catch (Exception ex) + { + NlogHelper.Warn($"从设备 {device.Name} 读取变量 {variable.Name} 失败:{ex.Message}"); + } + + } + private void ConnectS7Service() { try @@ -249,14 +263,7 @@ namespace PMSWPF.Services var plcClient = new Plc(device.CpuType, device.Ip, (short)device.Prot, device.Rack, device.Slot); plcClient.Open(); // 尝试打开连接。 // 将新创建的客户端添加到字典。 - if (_s7PlcClientDic.ContainsKey(device.Ip)) - { - _s7PlcClientDic[device.Ip] = plcClient; - } - else - { - _s7PlcClientDic.Add(device.Ip, plcClient); - } + _s7PlcClientDic[device.Ip] = plcClient; NotificationHelper.ShowSuccess($"已连接到S7 PLC: {device.Name} ({device.Ip})"); } @@ -267,6 +274,9 @@ namespace PMSWPF.Services } } + /// + /// 加载变量 + /// private void LoadVariables() { try @@ -291,17 +301,9 @@ namespace PMSWPF.Services .ToList(); // 将变量存储到字典中,方便以后通过ID快速查找 foreach (var s7Variable in s7Variables) - { - if (_variableDic.ContainsKey(s7Variable.Id)) - { - _variableDic[s7Variable.Id] = s7Variable; - } - else - { - _variableDic.Add(s7Variable.Id, s7Variable); - } - } + _variableDic[s7Variable.Id] = s7Variable; + varCount += s7Variables.Count(); _pollVariableDic.Add(device.Id, s7Variables); } @@ -320,28 +322,38 @@ namespace PMSWPF.Services /// public void StopService() { - NlogHelper.Info("S7后台服务正在关闭...."); - _stopEvent.Set(); - - _pollingThread.Interrupt(); - _serviceMainThread.Interrupt(); - DisconnectAllPlc(); - - foreach (Device device in _deviceDic.Values.ToList()) + try { - device.IsRuning = false; + NlogHelper.Info("S7后台服务正在关闭...."); + _stopEvent.Set(); + + _pollingThread.Interrupt(); + _serviceMainThread.Interrupt(); + DisconnectAllPlc(); + + foreach (Device device in _deviceDic.Values.ToList()) + { + device.IsRuning = false; + } + // 关闭事件 + _reloadEvent.Close(); + _stopEvent.Reset(); + _stopEvent.Close(); + // 清空所有字典。 + _deviceDic.Clear(); + _s7PlcClientDic.Clear(); + _pollVariableDic.Clear(); + NlogHelper.Info("S7后台服务已关闭"); + } + catch (Exception e) + { + NlogHelper.Error($"S7后台服务关闭时发生了错误:{e.Message}",e); } - // 关闭事件 - _reloadEvent.Close(); - _stopEvent.Reset(); - _stopEvent.Close(); - // 清空所有字典。 - _deviceDic.Clear(); - _s7PlcClientDic.Clear(); - _pollVariableDic.Clear(); - NlogHelper.Info("S7后台服务已关闭"); } + /// + /// 关闭所有PLC的连接 + /// private void DisconnectAllPlc() { if (_s7PlcClientDic==null || _s7PlcClientDic.Count == 0) @@ -349,10 +361,17 @@ namespace PMSWPF.Services // 关闭所有活跃的PLC连接。 foreach (var plcClient in _s7PlcClientDic.Values.ToList()) { - if (plcClient.IsConnected) + try { - plcClient.Close(); - NlogHelper.Info($"关闭S7连接: {plcClient.IP}"); + if (plcClient.IsConnected) + { + plcClient.Close(); + NlogHelper.Info($"关闭S7连接: {plcClient.IP}"); + } + } + catch (Exception e) + { + NlogHelper.Error($"S7后台服务关闭{plcClient.IP},后台连接时发生错误:{e.Message}",e); } } }