2025-07-05 19:31:36 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Threading;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using Microsoft.Extensions.Hosting;
|
|
|
|
|
|
using MQTTnet;
|
|
|
|
|
|
using MQTTnet.Client;
|
|
|
|
|
|
using MQTTnet.Client.Options;
|
|
|
|
|
|
using PMSWPF.Models;
|
|
|
|
|
|
using PMSWPF.Services;
|
|
|
|
|
|
using PMSWPF.Helper;
|
|
|
|
|
|
using PMSWPF.Enums;
|
|
|
|
|
|
|
|
|
|
|
|
namespace PMSWPF.Services
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// MQTT后台服务,继承自BackgroundService,用于在后台管理MQTT连接和数据发布。
|
|
|
|
|
|
/// </summary>
|
2025-07-07 21:24:45 +08:00
|
|
|
|
public class MqttBackgroundService
|
2025-07-05 19:31:36 +08:00
|
|
|
|
{
|
|
|
|
|
|
// 数据服务实例,用于访问和操作应用程序数据,如MQTT配置和变量数据。
|
|
|
|
|
|
private readonly DataServices _dataServices;
|
2025-07-10 17:16:15 +08:00
|
|
|
|
|
2025-07-05 19:31:36 +08:00
|
|
|
|
// 存储MQTT客户端实例的字典,键为MQTT配置ID,值为IMqttClient对象。
|
|
|
|
|
|
private readonly Dictionary<int, IMqttClient> _mqttClients;
|
2025-07-10 17:16:15 +08:00
|
|
|
|
|
2025-07-05 19:31:36 +08:00
|
|
|
|
// 存储MQTT配置的字典,键为MQTT配置ID,值为Mqtt模型对象。
|
2025-07-13 18:05:31 +08:00
|
|
|
|
private readonly Dictionary<int, Mqtt> _mqttConfigDic;
|
2025-07-10 17:16:15 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-07-05 19:31:36 +08:00
|
|
|
|
// 定时器,用于周期性地执行数据发布任务。
|
|
|
|
|
|
private Timer _timer;
|
2025-07-13 18:05:31 +08:00
|
|
|
|
private Thread _serviceMainThread;
|
|
|
|
|
|
|
|
|
|
|
|
private ManualResetEvent _reloadEvent = new ManualResetEvent(false);
|
|
|
|
|
|
private ManualResetEvent _stopEvent = new ManualResetEvent(false);
|
2025-07-05 19:31:36 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构造函数,注入DataServices。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="dataServices">数据服务实例。</param>
|
|
|
|
|
|
public MqttBackgroundService(DataServices dataServices)
|
|
|
|
|
|
{
|
|
|
|
|
|
_dataServices = dataServices;
|
|
|
|
|
|
_mqttClients = new Dictionary<int, IMqttClient>();
|
2025-07-13 18:05:31 +08:00
|
|
|
|
_mqttConfigDic = new Dictionary<int, Mqtt>();
|
2025-07-05 19:31:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-07-07 21:24:45 +08:00
|
|
|
|
/// 启动MQTT后台服务。
|
2025-07-05 19:31:36 +08:00
|
|
|
|
/// </summary>
|
2025-07-07 21:24:45 +08:00
|
|
|
|
public async void StartService()
|
2025-07-05 19:31:36 +08:00
|
|
|
|
{
|
|
|
|
|
|
// 订阅MQTT列表和变量数据变化的事件,以便在数据更新时重新加载配置和数据。
|
|
|
|
|
|
_dataServices.OnMqttListChanged += HandleMqttListChanged;
|
2025-07-13 18:05:31 +08:00
|
|
|
|
NlogHelper.Info("Mqtt后台服务启动"); // 记录服务启动信息
|
|
|
|
|
|
_reloadEvent.Set();
|
|
|
|
|
|
_stopEvent.Reset();
|
|
|
|
|
|
_serviceMainThread = new Thread(Execute);
|
|
|
|
|
|
_serviceMainThread.IsBackground = true;
|
|
|
|
|
|
_serviceMainThread.Name = "MqttServiceMainThread";
|
|
|
|
|
|
_serviceMainThread.Start();
|
|
|
|
|
|
|
2025-07-05 19:31:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-13 18:05:31 +08:00
|
|
|
|
private void Execute()
|
2025-07-13 16:22:07 +08:00
|
|
|
|
{
|
2025-07-13 18:05:31 +08:00
|
|
|
|
while (!_stopEvent.WaitOne(0))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_dataServices.Mqtts==null || _dataServices.Mqtts.Count==0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_reloadEvent.Reset();
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_reloadEvent.WaitOne();
|
|
|
|
|
|
// 初始加载MQTT配置和变量数据。
|
|
|
|
|
|
LoadMqttConfigurations();
|
|
|
|
|
|
ConnectMqttClient();
|
|
|
|
|
|
|
|
|
|
|
|
_reloadEvent.Reset();
|
|
|
|
|
|
}
|
2025-07-13 16:22:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-13 18:05:31 +08:00
|
|
|
|
|
2025-07-05 19:31:36 +08:00
|
|
|
|
/// <summary>
|
2025-07-07 21:24:45 +08:00
|
|
|
|
/// 停止MQTT后台服务。
|
2025-07-05 19:31:36 +08:00
|
|
|
|
/// </summary>
|
2025-07-13 18:05:31 +08:00
|
|
|
|
public void StopService()
|
2025-07-05 19:31:36 +08:00
|
|
|
|
{
|
2025-07-13 18:05:31 +08:00
|
|
|
|
NlogHelper.Info("Mqtt后台服务开始停止...."); // 记录服务停止信息
|
2025-07-05 19:31:36 +08:00
|
|
|
|
|
2025-07-13 18:05:31 +08:00
|
|
|
|
_stopEvent.Set();
|
2025-07-05 19:31:36 +08:00
|
|
|
|
// 取消订阅事件。
|
|
|
|
|
|
_dataServices.OnMqttListChanged -= HandleMqttListChanged;
|
|
|
|
|
|
|
|
|
|
|
|
// 断开所有已连接的MQTT客户端。
|
2025-07-13 18:05:31 +08:00
|
|
|
|
foreach (var mqttId in _mqttClients.Keys.ToList())
|
2025-07-05 19:31:36 +08:00
|
|
|
|
{
|
2025-07-13 18:05:31 +08:00
|
|
|
|
var client=_mqttClients[mqttId];
|
|
|
|
|
|
var mqtt=_mqttConfigDic[mqttId];
|
|
|
|
|
|
mqtt.IsConnected = false;
|
2025-07-05 19:31:36 +08:00
|
|
|
|
if (client.IsConnected)
|
|
|
|
|
|
{
|
2025-07-13 18:05:31 +08:00
|
|
|
|
client.DisconnectAsync().GetAwaiter().GetResult();
|
2025-07-05 19:31:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-10 17:16:15 +08:00
|
|
|
|
|
2025-07-05 19:31:36 +08:00
|
|
|
|
// 清空所有字典。
|
|
|
|
|
|
_mqttClients.Clear();
|
2025-07-13 18:05:31 +08:00
|
|
|
|
_mqttConfigDic.Clear();
|
|
|
|
|
|
NlogHelper.Info("Mqtt后台服务已停止。"); // 记录服务停止信息
|
2025-07-05 19:31:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 加载并连接MQTT配置。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>表示异步操作的任务。</returns>
|
2025-07-13 18:05:31 +08:00
|
|
|
|
private void LoadMqttConfigurations()
|
2025-07-05 19:31:36 +08:00
|
|
|
|
{
|
2025-07-13 18:05:31 +08:00
|
|
|
|
NlogHelper.Info("开始加载Mqtt配置文件...");
|
2025-07-05 19:31:36 +08:00
|
|
|
|
// 从数据服务获取所有MQTT配置。
|
2025-07-13 18:05:31 +08:00
|
|
|
|
var _mqttConfigList = _dataServices.Mqtts.Where(m => m.IsActive)
|
|
|
|
|
|
.ToList();
|
|
|
|
|
|
foreach (var mqtt in _mqttConfigList)
|
2025-07-08 12:52:33 +08:00
|
|
|
|
{
|
2025-07-13 18:05:31 +08:00
|
|
|
|
_mqttConfigDic[mqtt.Id] = mqtt;
|
2025-07-08 12:52:33 +08:00
|
|
|
|
}
|
2025-07-13 18:05:31 +08:00
|
|
|
|
NlogHelper.Info($"Mqtt配置文件加载成功,开启的Mqtt客户端:{_mqttConfigList.Count}个。");
|
2025-07-05 19:31:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 连接到指定的MQTT代理。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="mqtt">MQTT配置对象。</param>
|
|
|
|
|
|
/// <returns>表示异步操作的任务。</returns>
|
2025-07-13 18:05:31 +08:00
|
|
|
|
private void ConnectMqttClient()
|
2025-07-05 19:31:36 +08:00
|
|
|
|
{
|
2025-07-13 18:05:31 +08:00
|
|
|
|
foreach (Mqtt mqtt in _mqttConfigDic.Values.ToList())
|
2025-07-05 19:31:36 +08:00
|
|
|
|
{
|
2025-07-13 18:05:31 +08:00
|
|
|
|
try
|
2025-07-05 19:31:36 +08:00
|
|
|
|
{
|
2025-07-13 18:05:31 +08:00
|
|
|
|
NlogHelper.Info($"开始连接:{mqtt.Name}的服务器...");
|
|
|
|
|
|
// 创建MQTT客户端工厂和客户端实例。
|
|
|
|
|
|
var factory = new MqttFactory();
|
|
|
|
|
|
var client = factory.CreateMqttClient();
|
|
|
|
|
|
// 构建MQTT客户端连接选项。
|
|
|
|
|
|
var options = new MqttClientOptionsBuilder()
|
|
|
|
|
|
.WithClientId(mqtt.ClientID)
|
|
|
|
|
|
.WithTcpServer(mqtt.Host, mqtt.Port)
|
|
|
|
|
|
.WithCredentials(mqtt.UserName, mqtt.PassWord)
|
|
|
|
|
|
.WithCleanSession() // 清理会话,每次连接都是新会话
|
|
|
|
|
|
.Build();
|
|
|
|
|
|
|
|
|
|
|
|
// 设置连接成功事件处理程序。
|
|
|
|
|
|
client.UseConnectedHandler(e =>
|
2025-07-05 19:31:36 +08:00
|
|
|
|
{
|
2025-07-13 18:05:31 +08:00
|
|
|
|
NotificationHelper.ShowSuccess($"已连接到MQTT服务器: {mqtt.Name}");
|
|
|
|
|
|
mqtt.IsConnected = true;
|
|
|
|
|
|
});
|
2025-07-05 19:31:36 +08:00
|
|
|
|
|
2025-07-13 18:05:31 +08:00
|
|
|
|
// 设置断开连接事件处理程序。
|
|
|
|
|
|
client.UseDisconnectedHandler(async e =>
|
2025-07-05 19:31:36 +08:00
|
|
|
|
{
|
2025-07-13 18:05:31 +08:00
|
|
|
|
NotificationHelper.ShowWarn($"与MQTT服务器断开连接: {mqtt.Name}");
|
|
|
|
|
|
mqtt.IsConnected = false;
|
|
|
|
|
|
// 服务停止
|
|
|
|
|
|
if (_stopEvent.WaitOne(0))
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
NlogHelper.Info($"5秒后重新连接Mqtt服务器:{mqtt.Name}");
|
|
|
|
|
|
// 尝试重新连接。
|
|
|
|
|
|
await Task.Delay(TimeSpan.FromSeconds(5)); // 等待5秒后重连
|
|
|
|
|
|
try
|
2025-07-05 19:31:36 +08:00
|
|
|
|
{
|
2025-07-13 18:05:31 +08:00
|
|
|
|
await client.ConnectAsync(options, CancellationToken.None);
|
2025-07-05 19:31:36 +08:00
|
|
|
|
}
|
2025-07-13 18:05:31 +08:00
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
NlogHelper.Error($"重新与Mqtt服务器连接失败: {mqtt.Name}", ex);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试连接到MQTT代理。
|
|
|
|
|
|
client.ConnectAsync(options, CancellationToken.None)
|
|
|
|
|
|
.GetAwaiter()
|
|
|
|
|
|
.GetResult();
|
|
|
|
|
|
// 将连接成功的客户端添加到字典。
|
|
|
|
|
|
_mqttClients[mqtt.Id] = client;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
NotificationHelper.ShowError($"连接MQTT服务器失败: {mqtt.Name} - {ex.Message}", ex);
|
2025-07-05 19:31:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-13 18:05:31 +08:00
|
|
|
|
|
2025-07-05 19:31:36 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 处理MQTT列表变化事件的回调方法。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="sender">事件发送者。</param>
|
|
|
|
|
|
/// <param name="mqtts">更新后的MQTT配置列表。</param>
|
2025-07-13 18:05:31 +08:00
|
|
|
|
private async void HandleMqttListChanged(List<Mqtt> mqtts)
|
2025-07-05 19:31:36 +08:00
|
|
|
|
{
|
2025-07-13 18:05:31 +08:00
|
|
|
|
NlogHelper.Info("Mqtt列表发生了变化,正在重新加载数据..."); // 记录MQTT列表变化信息
|
2025-07-05 19:31:36 +08:00
|
|
|
|
// 重新加载MQTT配置和变量数据。
|
2025-07-13 18:05:31 +08:00
|
|
|
|
_reloadEvent.Set();
|
2025-07-05 19:31:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-10 17:16:15 +08:00
|
|
|
|
}
|