Bootstrap

C#订阅mqtt主题

C#订阅mqtt主题

MQTT搭建

涉及到MQTT服务器的搭建和主题发布,请看这篇文章Windows系统搭建MQTT服务器和安装MQTTX客户端_windows mqttx的安装使用-CSDN博客即可。

创建一个C#项目

文章中用到的代码在这里可以找到:

通过百度网盘分享的文件:C#MQTT.zip
链接:https://pan.baidu.com/s/1fK7kvo2ZPR88Ve3sBGy4wQ
提取码:8778
–来自百度网盘超级会员V5的分享

这里以创建一个wpf项目为例子,进行说明

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

安装MQTTnet

要订阅mqtt相关的内容,我们需要下载一个C#的包MQTTNet客户端。
在这里插入图片描述
这里安装的是MQTTnet4.3.7.1207这个版本。
在这里插入图片描述
安装成功之后,在已安装的选型中,可以找到对应的安装内容。
在这里插入图片描述
也可以在右侧对应的选项中,确认是否已经安装了MQTTnet这个客户端。
在这里插入图片描述
在这里插入图片描述
双击按钮,可以跳转到对应的C#代码位置。

代码

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows;
using MQTTnet.Client;
using MQTTnet.Packets;
using MQTTnet.Protocol;
using MQTTnet;

namespace MqttHelloWorld
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        // mqtt连接客户端,这里添加一个?是声明可为null
        IMqttClient? mqttClient;
        public MainWindow()
        {
            InitializeComponent();
        }
        /**
         * 订阅消息按钮
         */
        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            // Console.WriteLine("订阅消息==========================================订阅消息");
            System.Diagnostics.Debug.WriteLine("订阅消息==========================================订阅消息");

            
            // 这一个判断是,为了保证只建立一个连接,如果去掉,每点击一次订阅主题按钮,建立一个连接。
            // 到时候,就是多个连接了
            if (mqttClient != null)
            {
                // 取消连接
                await mqttClient.DisconnectAsync();
                mqttClient = null;

            }

            var factory = new MqttFactory();
            mqttClient = factory.CreateMqttClient();
            var options = new MqttClientOptionsBuilder()
                  //.WithClientId("mqtttest") // 这里设置MQTT的连接的客户端id,这一步使用自动生成的字符串,也可以自定义
                  .WithTcpServer("127.0.0.1", 1883) // MQTT代理地址和端口
                                                    // .WithCredentials("admin", "public") // 如果MQTT服务器开启了匿名访问,这一句可以直接省略
                  .Build();
            // // 这个await不能省略,否则就有可能连接MQTT服务器失败,添加了await就需要在方法/函数上加async
            await mqttClient.ConnectAsync(options);

            var suboption = new MqttClientSubscribeOptions()
            {
                TopicFilters = new List<MqttTopicFilter>
                {
                    new MqttTopicFilterBuilder()
                        .WithTopic("zheshizhuti") // 这里设置订阅的主题,"#" 是一个通配符,代表订阅所有主题
                        .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce) // 设置QoS级别为至少一次
                        .Build()
                }
            };
            // 这个await不能省略,否则就是订阅不了,添加了await就需要在方法/函数上加async
            await mqttClient.SubscribeAsync(suboption);

            mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync;


        }

        private Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg)
        {
            System.Diagnostics.Debug.WriteLine("====================这个是订阅的主题消息======================");
            System.Diagnostics.Debug.WriteLine(arg.ApplicationMessage.ConvertPayloadToString());
            System.Diagnostics.Debug.WriteLine("====================这个是订阅的主题消息======================");
            return null;
        }

        /**
        * 取消订阅消息按钮
        */
        private async void Button_Click_1(object sender, RoutedEventArgs e)
        {
            if (mqttClient != null)
            {
                await mqttClient.UnsubscribeAsync("zheshizhuti");
                System.Diagnostics.Debug.WriteLine("取消订阅消息++++++++++++++++++++++++++++++++++++取消订阅消息");
                // 取消连接
                await mqttClient.DisconnectAsync();

                mqttClient = null;

            }
            
        }
    }
}

在这里插入图片描述
运行成功之后
在这里插入图片描述
在这里插入图片描述
清除日志之后,就可以跟方便在控制台中看后面订阅的主题内容了。
在这里插入图片描述

确认是否连接成功

确认是否连接成功了,登录emqx的管理界面。
在这里插入图片描述

使用MQTTX客户端发布主题内容

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

订阅成功了但是没有收到消息

这里我遇到过一个问题,就是明明订阅成功了,但是在MqttClient_ApplicationMessageReceivedAsync这个方法/函数中(具体看后面的代码)。就是收不到发布的主题信息内容,打断点也不行,程序运行也不报错。发现这个问题,是因为我想将字符串转换成JSON数据,然后拿到某个字段属性的值。那么造成这个问题的原因是什么呢?问题就是我引用了Newtonsoft.Json这个包。
在这里插入图片描述
这个是在.net4.8版本的时候遇到的情况,在.net6版本,并没有这个问题,也能正常订阅,拿到消息。后面是怎么解决的呢?我把Newtonsoft.Josn这个库删除了,不用它了。我使用了另外一个C#的JSON库,如果你使用的是.NET Core.NET 5/6/7等新版框架,可能需要通过NuGet包管理器安装Microsoft.Extensions.Json包来使用Json.NET,也就是内置了System.Text.Json这个库。因为低版本没有内置这个库,所以我是使用安装的方式引用的,但是在.net6中可以直接使用,不需要下载什么包之类的。因为这里使用的是高版本的.net6,所以两种方式都可以。

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows;
using MQTTnet.Client;
using MQTTnet.Packets;
using MQTTnet.Protocol;
using MQTTnet;
using Newtonsoft.Json.Linq;
using System.Text.Json;

namespace MqttHelloWorld
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        // mqtt连接客户端,这里添加一个?是声明可为null
        IMqttClient? mqttClient;
        public MainWindow()
        {
            InitializeComponent();
        }
        /**
         * 订阅消息按钮
         */
        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            // Console.WriteLine("订阅消息==========================================订阅消息");
            System.Diagnostics.Debug.WriteLine("订阅消息==========================================订阅消息");

            
            // 这一个判断是,为了保证只建立一个连接,如果去掉,每点击一次订阅主题按钮,建立一个连接。
            // 到时候,就是多个连接了
            if (mqttClient != null)
            {
                // 取消连接
                await mqttClient.DisconnectAsync();
                mqttClient = null;

            }

            var factory = new MqttFactory();
            mqttClient = factory.CreateMqttClient();
            var options = new MqttClientOptionsBuilder()
                  //.WithClientId("mqtttest") // 这里设置MQTT的连接的客户端id,这一步使用自动生成的字符串,也可以自定义
                  .WithTcpServer("127.0.0.1", 1883) // MQTT代理地址和端口
                                                    // .WithCredentials("admin", "public") // 如果MQTT服务器开启了匿名访问,这一句可以直接省略
                  .Build();
            // // 这个await不能省略,否则就有可能连接MQTT服务器失败,添加了await就需要在方法/函数上加async
            await mqttClient.ConnectAsync(options);

            var suboption = new MqttClientSubscribeOptions()
            {
                TopicFilters = new List<MqttTopicFilter>
                {
                    new MqttTopicFilterBuilder()
                        .WithTopic("zheshizhuti") // 这里设置订阅的主题,"#" 是一个通配符,代表订阅所有主题
                        .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce) // 设置QoS级别为至少一次
                        .Build()
                }
            };
            // 这个await不能省略,否则就是订阅不了,添加了await就需要在方法/函数上加async
            await mqttClient.SubscribeAsync(suboption);

            mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync;


        }

        private Task MqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg)
        {
            System.Diagnostics.Debug.WriteLine("====================这个是订阅的主题消息======================");
            System.Diagnostics.Debug.WriteLine(arg.ApplicationMessage.ConvertPayloadToString());
            var message = arg.ApplicationMessage.ConvertPayloadToString();

            JObject json = JObject.Parse(message);
            string msg1 = json["msg"].ToString();
            System.Diagnostics.Debug.WriteLine("这是内容msg1:====》" + msg1);

            var jsons = JsonDocument.Parse(message);
            var msg2 = jsons.RootElement.GetProperty("msg");
            System.Diagnostics.Debug.WriteLine("这是内容msg2:====》" + msg2);

            System.Diagnostics.Debug.WriteLine("====================这个是订阅的主题消息======================");
            return null;
        }

        /**
        * 取消订阅消息按钮
        */
        private async void Button_Click_1(object sender, RoutedEventArgs e)
        {
            if (mqttClient != null)
            {
                await mqttClient.UnsubscribeAsync("zheshizhuti");
                System.Diagnostics.Debug.WriteLine("取消订阅消息++++++++++++++++++++++++++++++++++++取消订阅消息");
                // 取消连接
                await mqttClient.DisconnectAsync();

                mqttClient = null;

            }
            
        }
    }
}

在这里插入图片描述
可以看到能够,正常拿到内容了,拿到对应JSON的属性值了。
在这里插入图片描述

;