服务器端
<UserControl
x:Class="DotNet6WPFDemon.Views.ServerView"
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:local="clr-namespace:DotNet6WPFDemon.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:prism="http://prismlibrary.com/"
d:DesignHeight="450"
d:DesignWidth="800"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d">
<md:TransitioningContent OpeningEffect="{md:TransitionEffect Kind=ExpandIn}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="2*" />
<RowDefinition Height="3*" />
<RowDefinition Height="0.5*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel
Grid.Row="0"
Margin="10,0,0,0"
VerticalAlignment="Center"
Orientation="Horizontal" />
<StackPanel
Grid.Row="1"
Margin="10,0,0,0"
VerticalAlignment="Center"
Orientation="Horizontal" />
</Grid>
<Grid Grid.Column="1">
<Border>
<StackPanel>
<TextBlock
Margin="10,20,10,10"
HorizontalAlignment="Center"
FontSize="30"
Text="MQTT服务器端" />
</StackPanel>
</Border>
</Grid>
</Grid>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel
Grid.Row="0"
Margin="10,0,0,0"
VerticalAlignment="Center"
Orientation="Horizontal">
<TextBlock
Width="70"
Margin="50,0,10,0"
FontSize="18"
Text="服务器Ip" />
<TextBox
Width="200"
Margin="10,0,0,0"
Text="{Binding Ip}" />
</StackPanel>
<StackPanel
Grid.Row="1"
Margin="10,0,0,0"
VerticalAlignment="Center"
Orientation="Horizontal">
<TextBlock
Width="70"
Margin="50,0,10,0"
FontSize="18"
Text="端口号" />
<TextBox
Width="200"
Margin="10,0,0,0"
Background="Transparent"
Text="{Binding Port}" />
</StackPanel>
<StackPanel
Grid.Row="2"
HorizontalAlignment="Center"
Orientation="Horizontal">
<Button
Width="150"
Margin="5,5,5,5"
Command="{Binding Conn}"
CommandParameter="{Binding RelativeSource={RelativeSource Self}}"
Content="开启MQTT服务" />
<Button
Width="150"
Margin="10,5,5,5"
Command="{Binding SendMsg}"
Content="发送消息到客户端" />
</StackPanel>
</Grid>
<Border
Grid.Column="1"
Margin="10,10,10,10"
BorderBrush="DeepSkyBlue"
BorderThickness="5">
<StackPanel>
<TextBox Margin="10,10,10,10" Text="{Binding Msg}" />
</StackPanel>
</Border>
</Grid>
<Border
Grid.Row="2"
Margin="10,10,10,10"
BorderBrush="Orange"
BorderThickness="5">
<StackPanel>
<TextBox Margin="10,10,10,10" Text="{Binding TxtResult}" />
</StackPanel>
</Border>
</Grid>
</md:TransitioningContent>
</UserControl>
using DotNet6WPFDemon.Entities;
using DotNet6WPFDemon.Repository;
using MQTTnet;
using MQTTnet.Client.Options;
using MQTTnet.Server;
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace DotNet6WPFDemon.ViewModels
{
public class ServerViewModel:BindableBase
{
IMqttServer server;
List<User> users = new List<User>();
MyDbContext db;
private string ip = "127.0.0.1";
public string Ip
{
get { return ip; }
set { ip = value; RaisePropertyChanged(); }
}
private string port = "1883";
public string Port
{
get { return port; }
set { port = value; RaisePropertyChanged(); }
}
private string txtResult;
public string TxtResult
{
get { return txtResult; }
set { txtResult = value; RaisePropertyChanged(); }
}
private string msg;
public string Msg
{
get { return msg; }
set { msg = value; RaisePropertyChanged(); }
}
public DelegateCommand<Button> Conn { get; private set; }
public DelegateCommand SendMsg { get; private set; }
public ServerViewModel()
{
//Conn = new DelegateCommand<Button>(ExecuteAsync);
Conn = new DelegateCommand<Button>(async (t) =>
{
if (!(t is Button))
{
return;
}
var optBuilder = new MqttServerOptionsBuilder().WithDefaultEndpointBoundIPAddress(IPAddress.Parse(Ip))
.WithDefaultEndpointPort(1883).WithConnectionValidator(c =>
{
using (db = new MyDbContext())
{
//在数据库中判断用户名和密码
User? user = db.Users.Where(us => us.Name == c.Username && us.Password == c.Password).FirstOrDefault();
if (user == null)
{
c.ReasonCode = MQTTnet.Protocol.MqttConnectReasonCode.BadUserNameOrPassword;
return;
}
}
c.ReasonCode = MQTTnet.Protocol.MqttConnectReasonCode.Success;
users.Add(new User()
{
ClientId = c.ClientId,
Name = c.Username,
Password = c.Password
});
TxtResult = $"{DateTime.Now}:帐号:{c.Username} 已经订阅! \r\n";
//显示订阅者的信息
}).WithSubscriptionInterceptor(c =>
{
if (c == null) return;
c.AcceptSubscription = true;
TxtResult += $"{DateTime.Now}:订阅者:{c.ClientId} \r\n";
//显示客户端来的消息
}).WithApplicationMessageInterceptor(c =>
{
if (c == null) return;
c.AcceptPublish = true;
string? str = c.ApplicationMessage?.Payload == null ? null : Encoding.UTF8.GetString(c.ApplicationMessage?.Payload) + "\r\n";
TxtResult += $"{DateTime.Now}:{str}\r\n";
});
//实例化MQTT服务器
server = new MqttFactory().CreateMqttServer();
//判断客户端是否断开了连接
server.UseClientDisconnectedHandler(c =>
{
var use = users.FirstOrDefault(t => t.ClientId == c.ClientId);
if (use != null)
{
users.Remove(use);
TxtResult += $"{DateTime.Now}:订阅者{use.Name}已经退出了 \r\n";
}
});
await server.StartAsync(optBuilder.Build());
MessageBox.Show("服务器开启成功!");
t.IsEnabled = false;
});
SendMsg = new DelegateCommand(() =>
{
foreach (var item in users)
{
server.PublishAsync(new MqttApplicationMessage()
{
Topic = item.ClientId,
QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.ExactlyOnce,
Retain = false,
Payload = Encoding.UTF8.GetBytes($"{DateTime.Now}:{Msg}")
});
}
//Msg = null;
});
}
}
}
客户端
<UserControl
x:Class="DotNet6WPFDemon.Views.ClientView"
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:local="clr-namespace:DotNet6WPFDemon.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:prism="http://prismlibrary.com/"
d:DesignHeight="450"
d:DesignWidth="800"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d">
<md:TransitioningContent OpeningEffect="{md:TransitionEffect Kind=ExpandIn}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="2*" />
<RowDefinition Height="3*" />
<RowDefinition Height="0.5*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel
Grid.Row="0"
Margin="10,0,0,0"
VerticalAlignment="Center"
Orientation="Horizontal">
<TextBlock
Width="70"
Margin="50,0,10,0"
FontSize="18"
Text="服务器Ip" />
<TextBox
Width="200"
Margin="10,0,0,0"
Text="{Binding Ip}" />
</StackPanel>
<StackPanel
Grid.Row="1"
Margin="10,0,0,0"
VerticalAlignment="Center"
Orientation="Horizontal">
<TextBlock
Width="70"
Margin="50,0,10,0"
FontSize="18"
Text="端口号" />
<TextBox
Width="200"
Margin="10,0,0,0"
Background="Transparent"
Text="{Binding Port}" />
</StackPanel>
</Grid>
<Grid Grid.Column="1">
<Border>
<StackPanel>
<TextBlock
Margin="10,20,10,10"
HorizontalAlignment="Center"
FontSize="30"
Text="MQTT客户端" />
</StackPanel>
</Border>
</Grid>
</Grid>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel
Grid.Row="0"
Margin="10,0,0,0"
VerticalAlignment="Center"
Orientation="Horizontal">
<TextBlock
Width="70"
Margin="50,0,10,0"
FontSize="18"
Text="用户名" />
<TextBox
Width="200"
Margin="10,0,0,0"
Text="{Binding UserName}" />
</StackPanel>
<StackPanel
Grid.Row="1"
Margin="10,0,0,0"
VerticalAlignment="Center"
Orientation="Horizontal">
<TextBlock
Width="70"
Margin="50,0,10,0"
FontSize="18"
Text="密码" />
<TextBox
Width="200"
Margin="10,0,0,0"
Background="Transparent"
Style="{StaticResource MyTextStyle}"
Text="{Binding Pwd}" />
</StackPanel>
<StackPanel
Grid.Row="2"
HorizontalAlignment="Center"
Orientation="Horizontal">
<Button
Width="150"
Margin="5,5,5,5"
Command="{Binding Conn}"
Content="连接MQTT服务器" />
<Button
Width="150"
Margin="10,5,5,5"
Command="{Binding SendMsg}"
Content="发送消息到服务器" />
</StackPanel>
</Grid>
<Border
Grid.Column="1"
Margin="10,10,10,10"
BorderBrush="DeepSkyBlue"
BorderThickness="5">
<StackPanel>
<TextBox Margin="10,10,10,10" Text="{Binding Msg}" />
</StackPanel>
</Border>
</Grid>
<Border
Grid.Row="2"
Margin="10,10,10,10"
BorderBrush="Orange"
BorderThickness="5">
<StackPanel>
<TextBox Margin="10,10,10,10" Text="{Binding TxtResult}" />
</StackPanel>
</Border>
</Grid>
</md:TransitioningContent>
</UserControl>
using DotNet6WPFDemon.Repository;
using DotNet6WPFDemon.Views;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DotNet6WPFDemon.ViewModels
{
public class ClientViewModel:BindableBase
{
IMqttClient client;
string? clientId = "";
MyDbContext db;
private string userName = "Zg";
public string UserName
{
get { return userName; }
set { userName = value; RaisePropertyChanged(); }
}
private string pwd = "123";
public string Pwd
{
get { return pwd; }
set { pwd = value; RaisePropertyChanged(); }
}
private string ip = "127.0.0.1";
public string Ip
{
get { return ip; }
set { ip = value; RaisePropertyChanged(); }
}
private string port = "1883";
public string Port
{
get { return port; }
set { port = value; RaisePropertyChanged(); }
}
private string txtResult;
public string TxtResult
{
get { return txtResult; }
set { txtResult = value; RaisePropertyChanged(); }
}
private string msg;
public string Msg
{
get { return msg; }
set { msg = value; RaisePropertyChanged(); }
}
public DelegateCommand Conn { get; private set; }
public DelegateCommand SendMsg { get; private set; }
public ClientViewModel()
{
Conn = new DelegateCommand(async () =>
{
using (db = new MyDbContext())
{
clientId = db.Users.Where(u => u.Name == this.UserName).FirstOrDefault().ClientId;
}
var options = new MqttClientOptionsBuilder().WithTcpServer(Ip, Int32.Parse(Port))
.WithClientId(clientId).WithCredentials($"{UserName}", $"{Pwd}").Build();
client = new MqttFactory().CreateMqttClient();
client.UseConnectedHandler(async c =>
{
//订阅服务端消息
await client.SubscribeAsync(new TopicFilterBuilder().WithTopic(clientId).Build());
}).UseDisconnectedHandler(c =>
{
TxtResult+= c.Exception.Message;
}).UseApplicationMessageReceivedHandler(c =>
{
//if (c == null) return;
string str = Encoding.UTF8.GetString(c.ApplicationMessage.Payload);//接收服务器端消息并解码
TxtResult += $"{str}\r\n";
});
//启动连接
await client.ConnectAsync(options);
});
SendMsg = new DelegateCommand(() =>
{
var msg = new MqttApplicationMessageBuilder().WithTopic(clientId).WithPayload($"{DateTime.Now}:{Msg}")
.WithExactlyOnceQoS().WithRetainFlag().Build();//配置消息类型
client.PublishAsync(msg);
Msg = null;
});
}
}
}
源码:
https://download.csdn.net/download/helldoger/85513118
效果