MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol.
MQTTnet是.Net平台下的MQTT协议中间件,不用单独安装MQTT服务,使用非常方便。但是网上的开发教程都非常老,随着版本的升级,这些老的教程都不适用了,因此,个人摸索了下,在.Net 5平台下做了这套开发示例。
开发环境:VS2019+.net 5.0
新建包含服务端和客户端的解决方案,客户端使用From窗体模式,服务端使用命令行模式。
服务端和客服端通过NuGet搜索、安装、添加MQTTnet组件,我这里的版本是3.1.1,最新版。
下面讲解关键代码:
1、服务端:
static async Task Main(string[] args)
{
var optionsBuilder = new MqttServerOptionsBuilder()
.WithConnectionBacklog(100)
.WithDefaultEndpointPort(1883)
.WithConnectionValidator(c =>
{
if (c.ClientId.Length < 2)
{
c.ReasonCode = MqttConnectReasonCode.ClientIdentifierNotValid;
return;
}
if (c.Username != "user")
{
c.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;
return;
}
if (c.Password != "pwd")
{
c.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;
return;
}
c.ReasonCode = MqttConnectReasonCode.Success;
});
var mqttServer = new MqttFactory().CreateMqttServer();
await mqttServer.StartAsync(optionsBuilder.Build());
Console.WriteLine("mqtt服务已启动!端口号:1883,用户名:user,密码:pwd;");
Console.WriteLine("可输入指令,查看客户端:【clients】;退出【exit】");
while (true)
{
var inputString = Console.ReadLine().ToLower().Trim();
if (inputString == "exit")
{
mqttServer?.StopAsync();
Console.WriteLine("MQTT服务已停止!");
await mqttServer.StopAsync();
break;
}
else if (inputString == "clients")
{
foreach (var item in await mqttServer.GetClientStatusAsync())
{
Console.WriteLine($"客户端标识:{item.ClientId},协议版本:{item.ProtocolVersion}");
}
}
else
{
Console.WriteLine($"命令[{inputString}]无效!");
}
}
}
首先初始化mqtt服务的配置,主要是端口号,这里还包含了用户名、密码的验证,如果只用于测试这个用户验证可以不需要。后面的while循环支持用户查询指令,大家可以自行扩展。
2、客户端:
客户端登录mqtt服务端的代码,其中包含了接收到订阅消息的处理
private async Task ConnectMqttServerAsync()
{
// Create a new MQTT client.
if (mqttClient == null)
{
try
{
var factory = new MqttFactory();
mqttClient = factory.CreateMqttClient();
var options = new MqttClientOptionsBuilder()
.WithTcpServer(txtIp.Text, Convert.ToInt32(txtPort.Text)).WithCredentials(txtUsername.Text, txtPsw.Text).WithClientId(txtClientId.Text) // Port is optional
.Build();
await mqttClient.ConnectAsync(options, CancellationToken.None);
Invoke((new Action(() =>
{
txtReceiveMessage.AppendText($"连接到MQTT服务器成功!" + txtIp.Text);
})));
mqttClient.UseApplicationMessageReceivedHandler(e =>
{
Invoke((new Action(() =>
{
txtReceiveMessage.AppendText($">> {"### RECEIVED APPLICATION MESSAGE ###"}{Environment.NewLine}");
})));
Invoke((new Action(() =>
{
txtReceiveMessage.AppendText($">> Topic = {e.ApplicationMessage.Topic}{Environment.NewLine}");
})));
Invoke((new Action(() =>
{
txtReceiveMessage.AppendText($">> Payload = {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}{Environment.NewLine}");
})));
Invoke((new Action(() =>
{
txtReceiveMessage.AppendText($">> QoS = {e.ApplicationMessage.QualityOfServiceLevel}{Environment.NewLine}");
})));
Invoke((new Action(() =>
{
txtReceiveMessage.AppendText($">> Retain = {e.ApplicationMessage.Retain}{Environment.NewLine}");
})));
});
}
catch (Exception ex)
{
mqttClient = null;
Invoke((new Action(() =>
{
txtReceiveMessage.AppendText($"连接到MQTT服务器失败!" + Environment.NewLine + ex.Message + Environment.NewLine);
})));
}
}
}
接下来内容请参阅下一篇文章,将说明消息订阅、发布等代码。