C# MQTT客户端
使用的第三方库:MQTTnet
MQTT数据接收事件参数
namespace Demo { /// <summary> /// MQTT数据接收事件参数 /// </summary> public class MqttReceivedEventArgs : EventArgs { /// <summary> /// 主题 /// </summary> public string Topic { get; } /// <summary> /// 消息 /// </summary> public string Message { get; } /// <summary> /// 构造函数 /// </summary> /// <param name="topic"></param> /// <param name="message"></param> public MqttReceivedEventArgs(string topic, string message) { Topic = topic ?? throw new ArgumentNullException(nameof(topic)); Message = message ?? throw new ArgumentNullException(nameof(message)); } } }
MQTT本地客户端
using Microsoft.Extensions.Logging; using MQTTnet; using MQTTnet.Client; using MQTTnet.Protocol; using System.Text; namespace Demo { /// <summary> /// MQTT 本地客户端 /// </summary> public class MqttToLocalClient { /// <summary> /// 客户端ID /// </summary> private readonly string _clientId = "RcsMqttClient_" + Guid.NewGuid(); /// <summary> /// 服务器地址 /// </summary> private string _host = "127.0.0.1"; /// <summary> /// 服务器端口 /// </summary> private int _port = 1883; /// <summary> /// 是否需要重连 /// </summary> private bool _needToReconnect = true; /// <summary> /// 需要订阅的主题 /// </summary> private List<string> _topics = new(); /// <summary> /// 日志服务 /// </summary> private readonly ILogger? _logger; /// <summary> /// MQTT客户端 /// </summary> private IMqttClient? _mqttClient; /// <summary> /// MQTT客户端选项 /// </summary> private MqttClientOptions? _mqttClientOptions; /// <summary> /// 消息接收事件 /// </summary> public event Func<MqttReceivedEventArgs, Task>? MessageReceivedEvent; /// <summary> /// 构造函数 /// </summary> /// <param name="logger"></param> public MqttToLocalClient(ILogger<MqttToLocalClient>? logger = null) { _logger = logger; } /// <summary> /// 初始化 /// </summary> /// <param name="host"></param> /// <param name="port"></param> /// <param name="needToReconnect"></param> /// <returns></returns> public async Task InitAsync(string host = "127.0.0.1", int port = 1883, bool needToReconnect = true) { // 客户端参数 _host = host; _port = port; _needToReconnect = needToReconnect; // 创建连接 await ConnectAsync(); // 判断连接状态的线程 CheckConnectThread(); } /// <summary> /// 创建连接 /// </summary> /// <returns></returns> /// <exception cref="Exception"></exception> private async Task ConnectAsync() { // 客户端参数 _mqttClientOptions = new MqttClientOptionsBuilder() .WithTcpServer(_host, _port) .WithClientId(_clientId) .Build(); // 创建客户端 _mqttClient = new MqttFactory().CreateMqttClient(); // 连接成功事件 _mqttClient.ConnectedAsync += MqttClient_ConnectedAsync; // 断开连接事件 _mqttClient.DisconnectedAsync += MqttClient_DisconnectedAsync; // 消息接收事件 _mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync; // 开始连接 var result = await _mqttClient.ConnectAsync(_mqttClientOptions); if (result.ResultCode != MqttClientConnectResultCode.Success) { throw new Exception($"Mqtt connect fail, Result code {result.ResultCode}"); } } /// <summary> /// 订阅主题 /// </summary> /// <param name="topic"></param> /// <returns></returns> private async Task SubscribeAsync(string topic) { if (_mqttClient?.IsConnected == true) { var mqttSubscribeOptions = new MqttFactory().CreateSubscribeOptionsBuilder() .WithTopicFilter( f => { f.WithTopic(topic).WithQualityOfServiceLevel(MqttQualityOfServiceLevel.ExactlyOnce); }) .Build(); var response = await _mqttClient.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None); } } /// <summary> /// 订阅主题 /// </summary> /// <param name="topics"></param> /// <returns></returns> public async Task SubscribeAsync(List<string> topics) { if (_mqttClient?.IsConnected == true) { // 缓存 if (_topics != topics) { _topics = topics; } // 遍历 foreach (string topic in _topics) { await SubscribeAsync(topic); } } } /// <summary> /// 发布消息 /// </summary> /// <param name="topic"></param> /// <param name="message"></param> /// <param name="qos"></param> /// <returns></returns> public async Task PublishAsync(string topic, string message, int qos) { if (_mqttClient?.IsConnected == true) { _logger?.LogDebug("Mqtt message publish: {0}, {1}", topic, message); var applicationMessage = new MqttApplicationMessageBuilder() .WithTopic(topic) .WithPayload(message) .WithQualityOfServiceLevel((MqttQualityOfServiceLevel)qos) .Build(); await _mqttClient.PublishAsync(applicationMessage, CancellationToken.None); } } /// <summary> /// 连接成功事件 /// </summary> /// <param name="arg"></param> /// <returns></returns> private async Task MqttClient_ConnectedAsync(MqttClientConnectedEventArgs arg) { _logger?.LogInformation("Mqtt connected, IP: {0}, IsSessionPresent: {1}", _host, arg.ConnectResult.IsSessionPresent); await Task.CompletedTask; } /// <summary> /// 断开连接事件 /// </summary> /// <param name="arg"></param> /// <returns></returns> private async Task MqttClient_DisconnectedAsync(MqttClientDisconnectedEventArgs arg) { _logger?.LogInformation("Mqtt disconnected, IP: {0}, Reason: {1}, IsSessionPresent: {2}", _host, arg.Reason.ToString(), arg.ClientWasConnected); await Task.CompletedTask; } /// <summary> /// 消息接收事件 /// </summary> /// <param name="arg"></param> /// <returns></returns> private async Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg) { try { // 话题 string topic = arg.ApplicationMessage.Topic; // 接收的数据 byte[] data = arg.ApplicationMessage.PayloadSegment.ToArray(); // 接收的字符串 string message = Encoding.UTF8.GetString(data); _logger?.LogDebug("Mqtt message received: {0}, {1}", topic, message); // 数据接收事件 MessageReceivedEvent?.Invoke(new MqttReceivedEventArgs(topic, message)); await Task.CompletedTask; } catch (Exception ex) { _logger?.LogError(ex, "MQTT接收数据的线程报错"); } } /// <summary> /// 判断连接状态的线程 /// </summary> private void CheckConnectThread() { Task.Run(async () => { while (true) { try { // 判断连接状态 if (_needToReconnect && _mqttClient?.IsConnected != true) { // 重新连接 await ConnectAsync(); // 订阅主题 await SubscribeAsync(_topics); } } catch (Exception ex) { _logger?.LogError(ex, "MQTT判断连接状态的线程报错"); } await Task.Delay(1000); } }); } } }
MQTT远程客户端
using Microsoft.Extensions.Logging; using MQTTnet; using MQTTnet.Client; using MQTTnet.Protocol; using MQTTnet.Server; using System.Text; namespace Demo { /// <summary> /// MQTT 远程客户端 /// </summary> public class MqttToRemoteClient { /// <summary> /// 客户端ID /// </summary> private string? _clientId; /// <summary> /// 服务器地址 /// </summary> private string? _host; /// <summary> /// 服务器端口 /// </summary> private int _port = 1883; /// <summary> /// 是否需要重连 /// </summary> private bool _needToReconnect = true; /// <summary> /// 需要订阅的主题 /// </summary> private List<string> _topics = new(); /// <summary> /// 初始化标志 /// </summary> private bool _initFlag = false; /// <summary> /// 日志服务 /// </summary> private readonly ILogger? _logger; /// <summary> /// MQTT客户端 /// </summary> private IMqttClient? _mqttClient; /// <summary> /// MQTT客户端选项 /// </summary> private MqttClientOptions? _mqttClientOptions; /// <summary> /// MQTT客户端锁 /// </summary> private readonly object _lock = new(); /// <summary> /// 消息接收事件 /// </summary> public event Func<MqttReceivedEventArgs, Task>? MessageReceivedEvent; /// <summary> /// 构造函数 /// </summary> /// <param name="logger"></param> public MqttToRemoteClient(ILogger<MqttToLocalClient>? logger = null) { _logger = logger; } /// <summary> /// 初始化 /// </summary> public void Init() { if (_initFlag == false) { // 判断连接状态的线程 CheckConnectThread(); _initFlag = true; } } /// <summary> /// 更新MQTT信息 /// </summary> /// <param name="clientId"></param> /// <param name="host"></param> /// <param name="port"></param> /// <param name="needToReconnect"></param> /// <returns></returns> public async Task UpdMqttInfoAsync(string clientId, string host, int port = 1883, bool needToReconnect = true) { await Task.Run(() => { lock (_lock) { _clientId = clientId; _host = host; _port = port; _needToReconnect = needToReconnect; } }); } /// <summary> /// 创建连接 /// </summary> /// <returns></returns> /// <exception cref="Exception"></exception> private async Task ConnectAsync() { // 客户端参数 _mqttClientOptions = new MqttClientOptionsBuilder() .WithTcpServer(_host, _port) .WithClientId(_clientId) .Build(); // 创建客户端 _mqttClient = new MqttFactory().CreateMqttClient(); // 连接成功事件 _mqttClient.ConnectedAsync += MqttClient_ConnectedAsync; // 断开连接事件 _mqttClient.DisconnectedAsync += MqttClient_DisconnectedAsync; // 消息接收事件 _mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync; // 开始连接 var result = await _mqttClient.ConnectAsync(_mqttClientOptions); if (result.ResultCode != MqttClientConnectResultCode.Success) { throw new Exception($"Mqtt connect fail, Result code {result.ResultCode}"); } } /// <summary> /// 断开连接 /// </summary> /// <param name="needToReconnect"></param> /// <returns></returns> public async Task DisconnectAsync(bool needToReconnect = false) { await Task.Run(() => { lock (_lock) { _needToReconnect = needToReconnect; _mqttClient.DisconnectAsync().Wait(); } }); } /// <summary> /// 订阅主题 /// </summary> /// <param name="topic"></param> /// <returns></returns> private async Task SubscribeAsync(string topic) { if (_mqttClient?.IsConnected == true) { var mqttSubscribeOptions = new MqttFactory().CreateSubscribeOptionsBuilder() .WithTopicFilter( f => { f.WithTopic(topic).WithQualityOfServiceLevel(MqttQualityOfServiceLevel.ExactlyOnce); }) .Build(); var response = await _mqttClient.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None); } } /// <summary> /// 订阅主题 /// </summary> /// <param name="topics"></param> /// <returns></returns> public async Task SubscribeAsync(List<string> topics) { if (_mqttClient?.IsConnected == true) { // 缓存 if (_topics != topics) { _topics = topics; } // 遍历 foreach (string topic in _topics) { await SubscribeAsync(topic); } } } /// <summary> /// 发布消息 /// </summary> /// <param name="topic"></param> /// <param name="message"></param> /// <param name="qos"></param> /// <returns></returns> public async Task PublishAsync(string topic, string message, int qos) { if (_mqttClient?.IsConnected == true) { _logger?.LogDebug("Mqtt message publish: {0}, {1}", topic, message); var applicationMessage = new MqttApplicationMessageBuilder() .WithTopic(topic) .WithPayload(message) .WithQualityOfServiceLevel((MqttQualityOfServiceLevel)qos) .Build(); await _mqttClient.PublishAsync(applicationMessage, CancellationToken.None); } } /// <summary> /// 连接成功事件 /// </summary> /// <param name="arg"></param> /// <returns></returns> private async Task MqttClient_ConnectedAsync(MqttClientConnectedEventArgs arg) { _logger?.LogInformation("Mqtt connected, IP: {0}, IsSessionPresent: {1}", _host, arg.ConnectResult.IsSessionPresent); await Task.CompletedTask; } /// <summary> /// 断开连接事件 /// </summary> /// <param name="arg"></param> /// <returns></returns> private async Task MqttClient_DisconnectedAsync(MqttClientDisconnectedEventArgs arg) { _logger?.LogInformation("Mqtt disconnected, IP: {0}, Reason: {1}, IsSessionPresent: {2}", _host, arg.Reason.ToString(), arg.ClientWasConnected); await Task.CompletedTask; } /// <summary> /// 消息接收事件 /// </summary> /// <param name="arg"></param> /// <returns></returns> private async Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg) { try { // 话题 string topic = arg.ApplicationMessage.Topic; // 接收的数据 byte[] data = arg.ApplicationMessage.PayloadSegment.ToArray(); // 接收的字符串 string message = Encoding.UTF8.GetString(data); _logger?.LogDebug("Mqtt message received: {0}, {1}", topic, message); // 数据接收事件 MessageReceivedEvent?.Invoke(new MqttReceivedEventArgs(topic, message)); await Task.CompletedTask; } catch (Exception ex) { _logger?.LogError(ex, "MQTT接收数据的线程报错"); } } /// <summary> /// 判断连接状态的线程 /// </summary> private void CheckConnectThread() { Task.Run(async () => { while (true) { try { await Task.Run(() => { lock (_lock) { // 判断连接状态 if (_host != null && _needToReconnect && _mqttClient?.IsConnected != true) { // 重新连接 ConnectAsync().Wait(); // 订阅主题 SubscribeAsync(_topics).Wait(); } } }); } catch (Exception ex) { _logger?.LogError(ex, "MQTT判断连接状态的线程报错"); } await Task.Delay(1000); } }); } } }