MQTT消息发送和接收的实现

我是不会的,全是从网上搜的,最终整理拼合的可以使用了,使用C#和VS2019,MQTT使用3.1.0版本,需要注意的是不同的版本代码是不一样的,对于咱这种不会的,当然是以能用为主了,你要是安装的最新的4.0版本,那还是换换吧

首先需要在nuGet中引用下面的三个,MQTTnet 3.1.0、MQTTnet.Extensions.ManagedClient 3.1.0、Newtonsoft.json 10.0.1,如果不引用的话,代码中会有错误,自己还解决不了,白白浪费你时间

代码是可以完全跑起来的,我在本机上已经运行过了,.net 版本是4.5.2

 

 

一、服务端

服务端主要是设置你要监听哪个端口,是否要验证客户端的用户名和密码,然后开启服务监听就行了,代码里设置的用户名是test,密码是1234,可以根据实际换成数据库中的用户名密码来验证,对于接收到的消息,现在是直接显示,以后可以保存到日志文件中,也可以保存到数据库中。

using MQTTnet.Server;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Protocol;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MQTTnet.Client.Receiving;

namespace MQTT
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        int Port = 2023;
        IMqttServer server = new MqttFactory().CreateMqttServer();
        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void btn_start_Click(object sender, EventArgs e)
        {
            StartMQTTAsync();
        }

        //启动服务端
        public async Task StartMQTTAsync()
        {
            MqttServerOptionsBuilder serverOptions = new MqttServerOptionsBuilder();
            serverOptions.WithConnectionValidator(client =>
            {
                string Account = client.Username;
                string PassWord = client.Password;
                string clientid = client.ClientId;
                if (Account == "test" && PassWord == "1234")
                {
                    client.ReasonCode = MqttConnectReasonCode.Success;
                    Console.WriteLine("校验成功");
                }
                else
                {
                    client.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;
                    Console.WriteLine("校验失败");
                }
            });
            serverOptions.WithDefaultEndpointPort(Port);
            //服务启动
            server.StartedHandler = new MqttServerStartedHandlerDelegate((Action<EventArgs>)StartedHandler);
            //服务停止
            server.StoppedHandler = new MqttServerStoppedHandlerDelegate((Action<EventArgs>)StoppedHandler);
            //客户端连接事件
            server.ClientConnectedHandler = new MqttServerClientConnectedHandlerDelegate((Action<MqttServerClientConnectedEventArgs>)ClientConnectedHandler);
            //客户端断开连接事件
            server.ClientDisconnectedHandler = new MqttServerClientDisconnectedHandlerDelegate((Action<MqttServerClientDisconnectedEventArgs>)ClientDisconnectedHandler);
            //消息监听
            server.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate((Action<MqttApplicationMessageReceivedEventArgs>)MessageReceivedHandler);
            //客户端订阅主题事件
            server.ClientSubscribedTopicHandler = new MqttServerClientSubscribedHandlerDelegate((Action<MqttServerClientSubscribedTopicEventArgs>)ClientSubscribedTopicHandler);
            //客户端取消订阅主题事件
            server.ClientUnsubscribedTopicHandler = new MqttServerClientUnsubscribedTopicHandlerDelegate((Action<MqttServerClientUnsubscribedTopicEventArgs>)ClientUnsubscribedTopicHandler);
            await server.StartAsync(serverOptions.Build());
        }
        public void StartedHandler(EventArgs obj)
        {
            L1.Items.Add("MQTT程序已启动,监听端口:"+Port.ToString());
        }
        /// <summary>
        /// MQTT服务器停止事件
        /// </summary>
        /// <param name="obj"></param>
        private void StoppedHandler(EventArgs obj)
        {
            L1.Items.Add("MQTT程序已经关闭!");
        }



        /// <summary>
        /// 客户端连接到服务器事件
        /// </summary>
        /// <param name="obj"></param>
        private void ClientConnectedHandler(MqttServerClientConnectedEventArgs obj)
        {
            L1.Items.Add($"{obj.ClientId}此客户端已经连接到服务器");
        }

        /// <summary>
        /// 客户端断开连接事件
        /// </summary>
        /// <param name="obj"></param>
        private void ClientDisconnectedHandler(MqttServerClientDisconnectedEventArgs obj)
        {
            L1.Items.Add($"断开连接的客户端:{obj.ClientId}");
            L1.Items.Add($"断开连接类型:{obj.DisconnectType.ToString()}");
        }

        /// <summary>
        /// 收到各个客户端发送的消息
        /// </summary>
        /// <param name="obj"></param>
        private void MessageReceivedHandler(MqttApplicationMessageReceivedEventArgs obj)
        {
            L1.Items.Add("===================================================");
            L1.Items.Add("收到消息:");
            L1.Items.Add("消息时间:" + DateTime.Now.ToString()); ;
            L1.Items.Add($"客户端:{obj.ClientId}");
            L1.Items.Add($"主题:{obj.ApplicationMessage.Topic}");
            L1.Items.Add($"消息:{Encoding.UTF8.GetString(obj.ApplicationMessage.Payload)}");
            L1.Items.Add("+++++++++++++++++++++++++++++++++++++++++++++++++++");
            L1.Items.Add("");
        }

        /// <summary>
        /// 客户端订阅的主题
        /// </summary>
        /// <param name="obj"></param>
        private void ClientSubscribedTopicHandler(MqttServerClientSubscribedTopicEventArgs obj)
        {
            L1.Items.Add($"客户端:{obj.ClientId}");
            L1.Items.Add($"订阅主题:{obj.TopicFilter.Topic}");
        }

        /// <summary>
        /// 客户端取消订阅主题
        /// </summary>
        /// <param name="obj"></param>
        private void ClientUnsubscribedTopicHandler(MqttServerClientUnsubscribedTopicEventArgs obj)
        {
            L1.Items.Add($"客户端:{obj.ClientId}");
            L1.Items.Add($"取消订阅主题:{obj.TopicFilter}");
        }



        /// <summary>
        /// 关闭服务
        /// </summary>
        /// <returns></returns>
        public async Task StopAsync()
        {
            if (server != null)
            {
                if (server.IsStarted)
                {
                    await server.StopAsync();
                    server.Dispose();
                }
            }
        }

        private void btn_stop_Click(object sender, EventArgs e)
        {
            StopAsync();
        }
    }
}

二、客户端

客户端就是设置服务端的地址和端口,用户名和密码,然后订阅主题,然后发送消息,咱们不会,就用各种框框来直观的操作了,可根据需要设计成简洁界面的,更方便使用

不知道是客户端ID不能重复还是不能在一台电脑上开两个客户端,反正开两个客户端后会反复的连接和断开,留给你们试吧

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Options;
using MQTTnet.Client.Receiving;
using MQTTnet.Extensions.ManagedClient;
using MQTTnet.Formatter;
using Newtonsoft.Json;

namespace MQTT
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }
        private MqttClientOptions options;
        private IManagedMqttClient mqttClient;

        private void Form2_Load(object sender, EventArgs e)
        {
            CheckForIllegalCrossThreadCalls = false;
        }

        private async void OnSubscriberConnected(MqttClientConnectedEventArgs x)
        {
            L_info.Items.Add("已连接到MQTT服务器!");
        }


        private async void OnSubscriberDisconnected(MqttClientDisconnectedEventArgs x)
        {
            L_info.Items.Add("已断开MQTT服务器连接!");
        }

        private void OnSubscriberMessageReceived(MqttApplicationMessageReceivedEventArgs x)
        {
            var payloadString = x.ApplicationMessage.ConvertPayloadToString();

            payloadString = ConvertJsonString(payloadString);

            var item = $"{Environment.NewLine}Topic: {x.ApplicationMessage.Topic}{Environment.NewLine}Payload: {payloadString} {Environment.NewLine}QoS: {x.ApplicationMessage.QualityOfServiceLevel}";
            this.BeginInvoke((MethodInvoker)delegate
            {
                AppendReceiveMsg(item);
            });
        }


        private async Task SubscriberStart()
        {

            var tcpServer = txt_ip.Text.Trim().ToString();
            var tcpPort = int.Parse(txt_port.Text.Trim());
            var mqttUser = txt_yhm.Text.Trim();
            var mqttPassword = txt_pwd.Text.Trim();
            var mqttFactory = new MqttFactory();



            this.options = new MqttClientOptions
            {
                ClientId = "Client-1",
                ProtocolVersion = MqttProtocolVersion.V311,
                ChannelOptions = new MqttClientTcpOptions
                {
                    Server = tcpServer,
                    Port = tcpPort
                }
            };
            if (options.ChannelOptions == null)
            {
                throw new InvalidOperationException();
            }

            if (!string.IsNullOrEmpty(mqttUser))
            {
                options.Credentials = new MqttClientCredentials
                {
                    Username = mqttUser,
                    Password = Encoding.UTF8.GetBytes(mqttPassword)
                };
            }

            options.CleanSession = true;
            options.KeepAlivePeriod = TimeSpan.FromSeconds(5);

            this.mqttClient = mqttFactory.CreateManagedMqttClient();
            this.mqttClient.ConnectedHandler = new MqttClientConnectedHandlerDelegate((Action<MqttClientConnectedEventArgs>)OnSubscriberConnected);
            this.mqttClient.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate((Action<MqttClientDisconnectedEventArgs>)OnSubscriberDisconnected);
            this.mqttClient.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate((Action<MqttApplicationMessageReceivedEventArgs>)OnSubscriberMessageReceived);
            await this.mqttClient.StartAsync(
                new ManagedMqttClientOptions
                {
                    ClientOptions = options
                });
        }
        /// <summary>
        /// 发送MQTT消息
        /// </summary>
        /// <param name="dyh">订阅号</param>
        /// <param name="msg">具体发送的消息</param>
        private async void sengMsg(string dyh,string msg) 
        {
            var publish_topic = dyh;
            var publish_msg = msg;
            var message = new MqttApplicationMessageBuilder()
            .WithTopic(publish_topic)
            .WithPayload(publish_msg)
            .WithExactlyOnceQoS()
            .Build();

            if (this.mqttClient != null)
            {
                await this.mqttClient.PublishAsync(message);
            }
        }
        private void AppendReceiveMsg(string msg)
        {
            Invoke((new Action(() =>
            {
                L_info.Items.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss: ") + msg + Environment.NewLine + Environment.NewLine);
            })));
        }
        private void AppendSendMsg(string msg)
        {
            Invoke((new Action(() =>
            {
                L_info.Items.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss: ") + msg + Environment.NewLine);
            })));
        }

        private void AppendLogMsg(string msg)
        {
            Invoke((new Action(() =>
            {
                L_info.Items.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss: ") + msg + Environment.NewLine);
            })));
        }

        private string ConvertJsonString(string str)
        {
            try
            {
                //格式化json字符串
                JsonSerializer serializer = new JsonSerializer();
                TextReader tr = new StringReader(str);
                JsonTextReader jtr = new JsonTextReader(tr);
                object obj = serializer.Deserialize(jtr);
                if (obj != null)
                {
                    StringWriter textWriter = new StringWriter();
                    JsonTextWriter jsonWriter = new JsonTextWriter(textWriter)
                    {
                        Formatting = Formatting.Indented,
                        Indentation = 4,
                        IndentChar = ' '
                    };
                    serializer.Serialize(jsonWriter, obj);
                    return textWriter.ToString();
                }

                return str;
            }
            catch (Exception ex)
            {
                return str;
            }
        }

        private async void btn_open_Click(object sender, EventArgs e)
        {
            //打开MQTT连接
            if (this.mqttClient == null)
            {
                await SubscriberStart();
            }
        }

        private async void btn_close_Click(object sender, EventArgs e)
        {
            if (this.mqttClient == null)
            {
                return;
            }
            await this.mqttClient.StopAsync();
            this.mqttClient = null;

        }

        private async void btn_dingyue_Click(object sender, EventArgs e)
        {
            var topicFilter = new MqttTopicFilter { Topic = this.txt_dyh.Text.Trim() };
            await this.mqttClient.SubscribeAsync(topicFilter);
            L_info.Items.Add("已订阅消息!");
        }

        private void btn_quxiao_Click(object sender, EventArgs e)
        {

        }

        private void btn_send_Click(object sender, EventArgs e)
        {
            string dyh = txt_dyh.Text.Trim();
            string msg = txt_msg.Text.Trim();
            sengMsg(dyh, msg);
        }

        private void groupBox4_Enter(object sender, EventArgs e)
        {

        }
    }
}

 

最后,程序和你肯定有一个能跑起来的,祝你好运~

 

posted @ 2023-06-12 11:46  wjbych  阅读(3395)  评论(0编辑  收藏  举报