1、前言
上篇完成了winform版的mqtt服务器和客户端,实现了订阅和发布,效果666,长这样
这节要做的wpf版,长这样,效果也是帅BBBB帅,wpf技术是cs程序软件的福音。
wpf的基础知识和案例项目可以看我的另一个专栏系列文章,这里直接干搞,开发环境依然是vs2022,.netframework 4.8,mqttnet3.x。
WPF真入门教程
2、服务器搭建
1、创建项目方案
2、添加包组件MQTTNET
3、创建相关的目录及文件
样式文件CommonStyle.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><Style x:Key="ButtonStyle" TargetType="Button"><Setter Property="Background" Value="#3F85FF"></Setter><Setter Property="Foreground" Value="White"></Setter><Setter Property="FocusVisualStyle" Value="{x:Null}"></Setter><Setter Property="Margin" Value="5"></Setter><Setter Property="FontSize" Value="16"></Setter><!--模板的样式--><Setter Property="Template"><Setter.Value><!--Button单选按钮样式--><ControlTemplate TargetType="Button"><Grid ><Border Background="{TemplateBinding Background}" CornerRadius="5" ><TextBlock Margin="10 5 10 5" Text="{TemplateBinding Content}" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock></Border></Grid><ControlTemplate.Triggers><!--鼠标放上去时的触发器--><Trigger Property="IsMouseOver" Value="True"><Setter Property="Background" Value="DarkOliveGreen" ></Setter></Trigger></ControlTemplate.Triggers> </ControlTemplate></Setter.Value></Setter></Style>
</ResourceDictionary>
4、设置UI布局界面
<Window x:Class="MQTTNETServerWPF.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:MQTTNETServerWPF.ViewModel"mc:Ignorable="d" Background="Transparent" WindowStartupLocation="CenterScreen"FontSize="13" FontFamily="Microsoft YaHei" FontWeight="ExtraLight" Foreground="#333"Title="MainWindow" Height="550" Width="890"><WindowChrome.WindowChrome><WindowChrome GlassFrameThickness="-1"/></WindowChrome.WindowChrome><Window.DataContext><local:MainWindowViewModel/></Window.DataContext><Grid ShowGridLines="true" ><Grid.RowDefinitions><RowDefinition Height="70"/><RowDefinition/></Grid.RowDefinitions><TextBlock Grid.Row="0" FontWeight="Bold" Background="BlanchedAlmond" Text="WPF版MQTT服务器程序" FontSize="25" VerticalAlignment="Center" Margin="6,20,0,0" Foreground="#666" /><Grid Grid.Row="1"><Grid.ColumnDefinitions><ColumnDefinition Width="220"/><ColumnDefinition/></Grid.ColumnDefinitions><Border BorderBrush="#EEE" BorderThickness="0,0,1,0"/><!--左侧布局--><StackPanel Grid.Column="0" Margin="20" ><TextBlock Text="主机地址"/><TextBox Text="{Binding Server.ServerIP}" Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10" /><TextBlock Text="端口号" Margin="0,10,0,0"/><TextBox Text="{Binding Server.ServerPort}" Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10" /><TextBlock Text="连接账号" Margin="0,10,0,0"/><TextBox Text="{Binding Server.ServerName}" Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10" /><TextBlock Text="连接密码" Margin="0,10,0,0"/><TextBox Text="{Binding Server.ServerPwd}" Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10" /><Button Content="启动服务" Margin="0,30,0,0" Height="30" Command="{Binding StartCommand}" Style="{StaticResource ButtonStyle}" /><Button Content="停止服务" Margin="0,10" Height="30" Command="{Binding StopCommand}" Style="{StaticResource ButtonStyle}"/></StackPanel><!--右侧布局--><Grid Grid.Column="1"><Grid.RowDefinitions><RowDefinition Height="2*"/><RowDefinition Height="3*"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><GridSplitter VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Height="4" Background="#F7F9FA" Grid.ColumnSpan="2" Margin="0,0,3,0"/><Grid Margin="20,20,10,15"><Grid.RowDefinitions><RowDefinition Height="30"/><RowDefinition/></Grid.RowDefinitions><TextBlock Text="在线Client列表"/><ListBox Grid.Row="1" ItemsSource="{Binding ClientsList}"/></Grid><Grid Margin="10,20,20,15" Grid.Column="1"><Grid.RowDefinitions><RowDefinition Height="30"/><RowDefinition/></Grid.RowDefinitions><TextBlock Text="Topic主题列表"/><ListView Grid.Row="1" ItemsSource="{Binding TopicsList}"></ListView></Grid><Grid Grid.Row="1" Grid.ColumnSpan="2" Margin="20,10,20,20"><Grid.RowDefinitions><RowDefinition Height="30"/><RowDefinition/></Grid.RowDefinitions><TextBlock Text="消息"/><TextBox Grid.Row="1" x:Name="txtRich" ToolTip="右键清理内容" Text="{Binding ConnectWords}" Height="200" Background="White" VerticalContentAlignment="Top" Padding="3,0" Margin="10,9,10,10" ><!--添加一个右键菜单的功能,即清空--><TextBox.ContextMenu><ContextMenu><MenuItem x:Name="menuClear" Click="miClear_Click" Header="清空内容"></MenuItem></ContextMenu></TextBox.ContextMenu></TextBox></Grid></Grid></Grid></Grid>
</Window>
5、视图模型,属性绑定和命令绑定
完整代码:
using MQTTnet.Client.Receiving;
using MQTTnet;
using MQTTnet.Server;
using MQTTNETServerWPF.Command;
using MQTTNETServerWPF.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Collections.ObjectModel;
using MQTTnet.Certificates;
using MQTTnet.Protocol;
using System.Runtime.Remoting.Messaging;namespace MQTTNETServerWPF.ViewModel
{public class MainWindowViewModel : ViewModelBase{private IMqttServer mqttserver;//mqtt服务器List<TopicItem> Topics = new List<TopicItem>();public MainWindowViewModel(){//创建服务器对象mqttserver = new MqttFactory().CreateMqttServer();mqttserver.ApplicationMessageReceivedHandler =new MqttApplicationMessageReceivedHandlerDelegate(new Action<MqttApplicationMessageReceivedEventArgs>(Server_ApplicationMessageReceived));//绑定消息接收事件mqttserver.ClientConnectedHandler =new MqttServerClientConnectedHandlerDelegate(new Action<MqttServerClientConnectedEventArgs>(Server_ClientConnected));//绑定客户端连接事件mqttserver.ClientDisconnectedHandler = new MqttServerClientDisconnectedHandlerDelegate(new Action<MqttServerClientDisconnectedEventArgs>(Server_ClientDisconnected));//绑定客户端断开事件mqttserver.ClientSubscribedTopicHandler = new MqttServerClientSubscribedHandlerDelegate(new Action<MqttServerClientSubscribedTopicEventArgs>(Server_ClientSubscribedTopic));//绑定客户端订阅主题事件mqttserver.ClientUnsubscribedTopicHandler = new MqttServerClientUnsubscribedTopicHandlerDelegate(new Action<MqttServerClientUnsubscribedTopicEventArgs>(Server_ClientUnsubscribedTopic));//绑定客户端退订主题事件mqttserver.StartedHandler = new MqttServerStartedHandlerDelegate(new Action<EventArgs>(Server_Started));//绑定服务端启动事件mqttserver.StoppedHandler = new MqttServerStoppedHandlerDelegate(new Action<EventArgs>(Server_Stopped));//绑定服务端停止事件}#region 方法/// 绑定消息接收事件/// </summary>/// <param name="e"></param>private void Server_ApplicationMessageReceived(MqttApplicationMessageReceivedEventArgs e){string msg = e.ApplicationMessage.ConvertPayloadToString();WriteLog(">>> 收到消息:" + msg + ",QoS =" + e.ApplicationMessage.QualityOfServiceLevel + ",客户端=" + e.ClientId + ",主题:" + e.ApplicationMessage.Topic);}/// <summary>/// 绑定客户端连接事件/// </summary>/// <param name="e"></param>private void Server_ClientConnected(MqttServerClientConnectedEventArgs e){Task.Run(() =>{App.Current.Dispatcher.Invoke(() =>{this.ClientsList.Add(e.ClientId);});WriteLog(">>> 客户端" + e.ClientId + "连接");});}/// <summary>/// 绑定客户端断开事件/// </summary>/// <param name="e"></param>private void Server_ClientDisconnected(MqttServerClientDisconnectedEventArgs e){Task.Run(() =>{App.Current.Dispatcher.Invoke(() =>{this.ClientsList.Remove(e.ClientId);});WriteLog(">>> 客户端" + e.ClientId + "断开");});}/// <summary>/// 绑定客户端订阅主题事件/// </summary>/// <param name="e"></param>private void Server_ClientSubscribedTopic(MqttServerClientSubscribedTopicEventArgs e){Task.Run(() =>{App.Current.Dispatcher.Invoke(() =>{var topic = Topics.FirstOrDefault(t => t.Topic == e.TopicFilter.Topic);if (topic == null){topic = new TopicItem { Topic = e.TopicFilter.Topic, Count = 0 };Topics.Add(topic);}if (!topic.Clients.Exists(c => c == e.ClientId)){topic.Clients.Add(e.ClientId);topic.Count++;}this.TopicsList.Clear();foreach (var item in this.Topics){this.TopicsList.Add($"{item.Topic}:{item.Count}");}});WriteLog(">>> 客户端" + e.ClientId + "订阅主题" + e.TopicFilter.Topic);});}/// <summary>/// 绑定客户端退订主题事件/// </summary>/// <param name="e"></param>private void Server_ClientUnsubscribedTopic(MqttServerClientUnsubscribedTopicEventArgs e){Task.Run(() =>{App.Current.Dispatcher.Invoke(() =>{var topic = Topics.FirstOrDefault(t => t.Topic == e.TopicFilter);if (topic != null){topic.Count--;topic.Clients.Remove(e.ClientId);}this.TopicsList.Clear();foreach (var item in this.Topics){this.TopicsList.Add($"{item.Topic}:{item.Count}");}});WriteLog(">>> 客户端" + e.ClientId + "退订主题" + e.TopicFilter);});}/// <summary>/// 绑定服务端启动事件/// </summary>/// <param name="e"></param>private void Server_Started(EventArgs e){WriteLog(">>> 服务端已启动!");}/// <summary>/// 绑定服务端停止事件/// </summary>/// <param name="e"></param>private void Server_Stopped(EventArgs e){WriteLog(">>> 服务端已停止!");}/// <summary>/// 显示日志/// </summary>/// <param name="message"></param>public void WriteLog(string message){Task.Run(() =>{App.Current.Dispatcher.Invoke(() =>{ConnectWords = message + "\r";});});}#endregion#region 属性private MqttServerModel server = new MqttServerModel("127.0.0.1", "1869", "boss", "1234");//服务器实体/// <summary>/// 当前服务器对象/// </summary>public MqttServerModel Server{get { return server; }set{server = value;OnPropertyChanged();}}private string connectWords = "";/// <summary>/// 连接状态/// </summary>public string ConnectWords{get { return connectWords; }set{connectWords = value;OnPropertyChanged();}}private ObservableCollection<string> clientsList = new ObservableCollection<string>();/// <summary>/// 客户列表/// </summary>public ObservableCollection<string> ClientsList{get { return clientsList; }set{clientsList = value;OnPropertyChanged();}}private ObservableCollection<string> topicsList = new ObservableCollection<string>();/// <summary>/// 主题列表/// </summary>public ObservableCollection<string> TopicsList{get { return topicsList; }set{topicsList = value;OnPropertyChanged();}}#endregion#region 命令/// <summary>/// 启动命令/// </summary>[Obsolete]public ICommand StartCommand{get{return new RelayCommand(async o =>{var optionBuilder = new MqttServerOptionsBuilder().WithDefaultEndpointBoundIPAddress(System.Net.IPAddress.Parse(Server.ServerIP)).WithDefaultEndpointPort(int.Parse(Server.ServerPort)).WithDefaultCommunicationTimeout(TimeSpan.FromMilliseconds(5000)).WithConnectionValidator(t =>{string un = "", pwd = "";un = Server.ServerName;pwd = Server.ServerPwd;if (t.Username != un || t.Password != pwd){t.ReturnCode = MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword;}else{t.ReturnCode = MqttConnectReturnCode.ConnectionAccepted;}});var option = optionBuilder.Build();//启动await mqttserver.StartAsync(option);});}}/// <summary>/// 启动命令/// </summary>[Obsolete]public ICommand StopCommand{get{return new RelayCommand(async o =>{ if (server != null){await mqttserver.StopAsync();} });}}#endregion}
}
注意一个地方,就是给文本框添加了一个右键“清空”的功能,看看是怎么样实现的?
6、启动测试服务器
启动成功,服务器kokokokoko!!!!
3、客户端创建
1、添加项目MQTTNETClientWPF
2、添加客户端的组件
3、创建相关的类文件及目录
4、设计UI布局
布局仔细 看下
<Window x:Class="MQTTNETClientWPF.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:MQTTNETClientWPF.ViewModel"mc:Ignorable="d" Background="Transparent" WindowStartupLocation="CenterScreen"FontSize="13" FontFamily="Microsoft YaHei" FontWeight="ExtraLight" Foreground="#333"Title="MainWindow" Height="600" Width="850"><WindowChrome.WindowChrome><WindowChrome GlassFrameThickness="-1"/></WindowChrome.WindowChrome><Window.DataContext><local:MainWindowViewModel/></Window.DataContext><Grid ShowGridLines="true" ><Grid.RowDefinitions><RowDefinition Height="70"/><RowDefinition/></Grid.RowDefinitions><TextBlock Grid.Row="0" FontWeight="Bold" Text="WPF版MQTT客户端程序" FontSize="25" VerticalAlignment="Center" Margin="6,20,0,0" Foreground="#666" Background="BlanchedAlmond" /><Grid Grid.Row="1"><Grid.ColumnDefinitions><ColumnDefinition Width="220"/><ColumnDefinition/></Grid.ColumnDefinitions><Border BorderBrush="#EEE" BorderThickness="0,0,1,0"/><StackPanel Margin="20"><TextBlock Text="主机地址"/><TextBox Text="{Binding Client.ServerIP}" Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10" Name="tbHostAddr"/><TextBlock Text="端口号" Margin="0,5,0,0"/><TextBox Text="{Binding Client.ServerPort}" Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10" Name="tbHostPort"/><TextBlock Text="连接账号" Margin="0,5,0,0"/><TextBox Text="{Binding Client.ServerName}" Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10" Name="tbUsername"/><TextBlock Text="连接密码" Margin="0,5,0,0"/><TextBox Text="{Binding Client.ServerPwd}" Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10" Name="tbPassword"/><TextBlock Text="客户端ID" Margin="0,5,0,0"/><TextBox Text="{Binding Client.ClientId}" Height="30" VerticalContentAlignment="Center" Padding="5,0" Margin="0,10" Name="tbClientId"/><Button Content="连接" Margin="0,30,0,0" Height="30" Command="{Binding OpenCommand}" Style="{StaticResource ButtonStyle}"/><Button Content="断开" Margin="0,10" Height="30" Command="{Binding CloseCommand}" Style="{StaticResource ButtonStyle}"/></StackPanel><Grid Grid.Column="1" Margin="20,10"><Grid.RowDefinitions><RowDefinition Height="auto"/><RowDefinition Height="auto"/><RowDefinition/></Grid.RowDefinitions><Grid><Grid.RowDefinitions><RowDefinition Height="30"/><RowDefinition Height="50"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="auto"/><ColumnDefinition/><ColumnDefinition Width="auto"/></Grid.ColumnDefinitions><Border Background="#F7F9FA" Grid.ColumnSpan="3"/><TextBlock Text="订阅" VerticalAlignment="Center" Margin="5,0"/><TextBlock Text="主题" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5,0"/><TextBox Text="{Binding Topic}" Grid.Row="1" Height="30" Padding="5,0" VerticalContentAlignment="Center" Grid.Column="1" Name="tbTopic"/><Button Width="50" Grid.Row="1" Height="30" Content="订阅" Grid.Column="2" Margin="5,10,0,10" Command="{Binding SubscriteCommand}" Style="{StaticResource ButtonStyle}" HorizontalAlignment="Left"/></Grid><Grid Grid.Row="1" Margin="0,20"><Grid.RowDefinitions><RowDefinition Height="30"/><RowDefinition Height="50"/><RowDefinition Height="30"/><RowDefinition/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="auto"/><ColumnDefinition/><ColumnDefinition Width="auto"/></Grid.ColumnDefinitions><Border Background="#F7F9FA" Grid.ColumnSpan="3"/><TextBlock Text="发布" VerticalAlignment="Center" Margin="5,0"/><TextBlock Text="主题" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5,0"/><TextBox Text="{Binding Topic}" Grid.Row="1" Height="30" Padding="5,0" VerticalContentAlignment="Center" Grid.Column="1" Name="tbPubTopic"/><TextBlock Text="内容" Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5,0"/><TextBox Text="{Binding Pubmsg}" Grid.Row="2" Height="30" Padding="5,0" VerticalContentAlignment="Center" Grid.Column="1" Name="tbContent"/><Button Width="50" Grid.Row="2" Height="30" Content="发布" Grid.Column="2" Margin="5,0,5,0" Command="{Binding PublishCommand}" Style="{StaticResource ButtonStyle}" VerticalAlignment="Top"/></Grid><Grid Grid.Row="2" Margin="0,10,0,0"><Grid.RowDefinitions><RowDefinition Height="30"/><RowDefinition/></Grid.RowDefinitions><Border Background="#F7F9FA" Grid.ColumnSpan="3"/><TextBlock Text="消息" VerticalAlignment="Center" Margin="5,0"/><TextBox Grid.Row="1" x:Name="txtRich" ToolTip="右键清理内容" Text="{Binding ConnectWords}" Height="200" Background="White" VerticalContentAlignment="Top" Padding="3,0" Margin="10,9,75,10" ><!--添加一个右键菜单的功能,即清空--><TextBox.ContextMenu><ContextMenu><MenuItem x:Name="menuClear" Click="miClear_Click" Header="清空内容"></MenuItem></ContextMenu></TextBox.ContextMenu></TextBox></Grid></Grid></Grid></Grid>
</Window>
5、视图模型viewmodel
模型类的属性绑定和命令绑定,数据驱动控件,即Mvvm渲染方法
using MQTTnet.Client.Options;
using MQTTnet.Client;
using MQTTnet.Extensions.ManagedClient;
using MQTTNETClientWPF.Command;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using MQTTNETClientWPF.Model;
using MQTTnet;namespace MQTTNETClientWPF.ViewModel
{public class MainWindowViewModel : ViewModelBase{private IManagedMqttClient mqttClient; //mqtt客户端public MainWindowViewModel(){var factory = new MqttFactory();mqttClient = factory.CreateManagedMqttClient();//创建客户端对象//绑定断开事件mqttClient.UseDisconnectedHandler(async ee =>{WriteLog(DateTime.Now.ToString() + "与服务器之间的连接断开了,正在尝试重新连接");// 等待 5s 时间await Task.Delay(TimeSpan.FromSeconds(5));try{mqttClient.UseConnectedHandler(cc =>{WriteLog(">>> 连接到服务成功!");});}catch (Exception ex){Console.WriteLine($"重新连接服务器失败:{ex}");}});//绑定接收事件mqttClient.UseApplicationMessageReceivedHandler(aa =>{try{string msg = aa.ApplicationMessage.ConvertPayloadToString();WriteLog(">>> 消息:" + msg + ",QoS =" + aa.ApplicationMessage.QualityOfServiceLevel + ",客户端=" + aa.ClientId + ",主题:" + aa.ApplicationMessage.Topic);}catch (Exception ex){WriteLog($"+ 消息 = " + ex.Message);} });//绑定连接事件mqttClient.UseConnectedHandler(ee =>{WriteLog(">>> 连接到服务");});}/// <summary>/// 显示日志/// </summary>/// <param name="message"></param> public void WriteLog(string message){Task.Run(() =>{App.Current.Dispatcher.Invoke(() =>{ConnectWords = message + "\r";});});}#region 属性private MqttClientModel client = new MqttClientModel("127.0.0.1", "1869", "boss", "1234", "c1");//服务器实体/// <summary>/// 连接对象/// </summary>public MqttClientModel Client{get { return client; }set{client = value;OnPropertyChanged();}}private string connectWords = "";/// <summary>/// 连接状态/// </summary>public string ConnectWords{get { return connectWords; }set{connectWords = value;OnPropertyChanged();}}private string topic = "shanghai";/// <summary>/// 主题/// </summary>public string Topic{get { return topic; }set{topic = value;OnPropertyChanged();}}private string pubmsg = "0103";/// <summary>/// 发布/// </summary>public string Pubmsg{get { return pubmsg; }set{pubmsg = value;OnPropertyChanged();}}#endregion#region 命令/// <summary>/// 连接命令/// </summary> public ICommand OpenCommand{get{return new RelayCommand(async o =>{var mqttClientOptions = new MqttClientOptionsBuilder().WithClientId(this.Client.ClientId).WithTcpServer(this.Client.ServerIP, int.Parse(this.Client.ServerPort)).WithCredentials(this.Client.ServerName, this.Client.ServerPwd);var options = new ManagedMqttClientOptionsBuilder().WithAutoReconnectDelay(TimeSpan.FromSeconds(5)).WithClientOptions(mqttClientOptions.Build()).Build();//开启var t = mqttClientOptions;await mqttClient.StartAsync(options);});}}/// <summary>/// 断开命令/// </summary> public ICommand CloseCommand{get{return new RelayCommand(async o =>{if (mqttClient != null){if (mqttClient.IsStarted){await mqttClient.StopAsync();}mqttClient.Dispose();}});}}/// <summary>/// 订阅命令/// </summary> [Obsolete]public ICommand SubscriteCommand{get{return new RelayCommand(async o =>{if (string.IsNullOrWhiteSpace(this.Topic)){WriteLog(">>> 请输入主题");return;}//在 MQTT 中有三种 QoS 级别: //At most once(0) 最多一次//At least once(1) 至少一次//Exactly once(2) 恰好一次//await mqttClient.SubscribeAsync(new TopicFilterBuilder().WithTopic(this.tbTopic.Text).WithAtMostOnceQoS().Build());//最多一次, QoS 级别0await mqttClient.SubscribeAsync(new TopicFilterBuilder().WithTopic(this.Topic).WithAtLeastOnceQoS().Build());//恰好一次, QoS 级别1 WriteLog($">>> 成功订阅 {this.Topic}");});}}/// <summary>/// 发布命令/// </summary> public ICommand PublishCommand{get{return new RelayCommand(async o =>{if (string.IsNullOrWhiteSpace(this.Topic)){WriteLog(">>> 请输入主题");return;}var result = await mqttClient.PublishAsync(this.Topic,this.Pubmsg,MQTTnet.Protocol.MqttQualityOfServiceLevel.AtLeastOnce);//恰好一次, QoS 级别1 WriteLog($">>> 主题:{this.Topic},消息:{this.Pubmsg},结果: {result.ReasonCode}");});}}#endregion}
}
6、启动客户端
比较屌
4、测试mqtt
1、启动服务器,客户端连接成功
2、测试订阅
3、测试发布
再启动一个客户端程序,有人不知道如何启动,看下面
c1发布一个消息,看看c1,c2有没有收到,很明显都收到了
服务器显示有关信息,完全good
基于mqttnet实现的wpf版通信,完美实现,效果飞起来了,颜值高,效果好,帅B得上了飞机。
5、完整代码打包下载
链接:https://pan.baidu.com/s/1sfQnGEEcsRTBKUSDOdCeTA
提取码:z2hj
讲解不易,分析不易,原创不易,整理不易,伙伴们动动你的金手指,你的支持是我最大的动力。