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 级别0
await 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
讲解不易,分析不易,原创不易,整理不易,伙伴们动动你的金手指,你的支持是我最大的动力。