MQTT(⼀)C#使⽤MQTTnet快速实现MQTT通信(⽂末有完
整Demo下载)
⽬录
1 什么是 MQTT ?
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是 IBM 开发的⼀个即时通讯协议,有可能成为物联⽹的重要组成部分。MQTT 是基于⼆进制消息的发布/订阅编程模式的消息协议,如今已经成为 OASIS 规范,由于规范很简单,⾮常适合需要低功耗和⽹络带宽有限的 IoT 场景。
2 MQTTnet
是⼀个基于 MQTT 通信的⾼性能 开源库,它同时⽀持 MQTT 服务器端和客户端。⽽且作者也保持更新,⽬前⽀持新版的 core,这也是选择 MQTTnet 的原因。 MQTTnet 在 Github 并不是下载最多的 的 MQTT 开源库,其他的还 、、 等
3 创建项⽬并导⼊类库
这⾥我们使⽤ Visual Studio 2017 创建⼀个空解决⽅案,并在其中添加两个项⽬,即⼀个服务端和⼀个客户端,服务端项⽬模板选择最新的 Core 控制台应⽤,客户端项⽬选择传统的 WinForm 窗体应⽤程序。 Core 项⽬模板如下图所⽰:
在解决⽅案在右键单击-选择“管理解决⽅案的 NuGet 程序包”-在“浏览”选项卡下⾯搜索 MQTTnet,为
服务端项⽬和客户端项⽬都安装上 MQTTnet 库,当前最新稳定版为 2.4.0。项⽬结构如下图所⽰:
4 服务端
MQTT 服务端主要⽤于与多个客户端保持连接,并处理客户端的发布和订阅等逻辑。⼀般很少直接从服务端发送消息给客户端(可以使⽤ mqttServer.Publish(appMsg); 直接发送消息),多数情况下服务端都是转发主题匹配的客户端消息,在系统中起到⼀个中介的作⽤。
4.1 创建服务端并启动
创建服务端最简单的⽅式是采⽤ MqttServerFactory 对象的 CreateMqttServer ⽅法来实现,该⽅法需要⼀个MqttServerOptions 参数。
var options = new MqttServerOptions();
var mqttServer = new MqttServerFactory().CreateMqttServer(options);
频频点头的意思通过上述⽅式创建了⼀个 IMqttServer 对象后,调⽤其 StartAsync ⽅法即可启动 MQTT 服务。值得注意的是:之前版本采⽤的是 Start ⽅法,作者也是紧跟 C# 语⾔新特性,能使⽤异步的地⽅也都改为异步⽅式。
await mqttServer.StartAsync();
horpower
4.2 验证客户端
在 MqttServerOptions 选项中,你可以使⽤ ConnectionValidator 来对客户端连接进⾏验证。⽐如客户端ID标识 ClientId,⽤户bus的复数
名 Urname 和密码 Password 等。
var options = new MqttServerOptions
{
ConnectionValidator = c =>
{
if (c.ClientId.Length < 10)
{
return MqttConnectReturnCode.ConnectionRefudIdentifierRejected;
}
if (c.Urname != "xxx" || c.Password != "xxx")
{
return MqttConnectReturnCode.ConnectionRefudBadUrnameOrPassword;
}
return MqttConnectReturnCode.ConnectionAccepted;
}
};
4.3 相关事件
服务端⽀持 ClientConnected、ClientDisconnected 和 ApplicationMessageReceived 事件,分别⽤来检查客户端连接、客户端断开以及接收客户端发来的消息。
学日语有前途吗其中 ClientConnected 和 ClientDisconnected 事件的事件参数⼀个客户端连接对象 ConnectedMqttClient,通过该对象可以获取客户端ID标识 ClientId 和 MQTT 版本 ProtocolVersion。
ApplicationMessageReceived 的事件参数包含了客户端ID标识 ClientId 和 MQTT 应⽤消息 MqttAppli
cationMessage 对象,通过该对象可以获取主题 Topic、QoS QualityOfServiceLevel 和消息内容 Payload 等信息。
5 客户端
MQTT 与 HTTP 不同,后者是基于请求/响应⽅式的,服务器端⽆法直接发送数据给客户端。⽽ MQTT 是基于发布/订阅模式的,所有的客户端均与服务端保持连接状态。
那么客户端之间是如何通信的呢?
具体逻辑是:某些客户端向服务端订阅它感兴趣(主题)的消息,另⼀些客户端向服务端发布(主题)消息,服务端将订阅和发布的主题进⾏匹配,并将消息转发给匹配通过的客户端。
5.1 创建客户端并连接
使⽤ MQTTnet 创建 MQTT 也⾮常简单,只需要使⽤ MqttClientFactory 对象的 CreateMqttClient ⽅法即可。
var mqttClient = new MqttClientFactory().CreateMqttClient();
创建客户端对象后,调⽤其异步⽅法 ConnectAsync 来连接到服务端。
奠基人的意思await mqttClient.ConnectAsync(options);
调⽤该⽅法时需要传递⼀个 MqttClientTcpOptions 对象(之前的版本是在创建对象时使⽤该选项),该选项包含了客户端ID标识 ClientId、服务端地址(可以使⽤IP地址或域名)Server、端⼝号 Port、⽤户名 UrName、密码 Password 等信息。
var options = new MqttClientTcpOptions
{
whynotServer = "127.0.0.1",
ClientId = "c001",
UrName = "u001",
gagman
Password = "p001",
CleanSession = true
};
5.2 相关事件
客户端⽀持 Connected、Disconnected 和 ApplicationMessageReceived 事件,⽤来处理客户端与服务端连接、客户端从服务端断开以及客户端收到消息的事情。
5.2 订阅消息
客户端连接到服务端之后,可以使⽤ SubscribeAsync 异步⽅法订阅消息,该⽅法可以传⼊⼀个可枚举或可变参数的主题过滤
器 TopicFilter 参数,主题过滤器包含主题名和 QoS 等级。
mqttClient.SubscribeAsync(new List<TopicFilter> {
new TopicFilter("家/客厅/空调/#", MqttQualityOfServiceLevel.AtMostOnce)
});
5.3 发布消息
发布消息前需要先构建⼀个消息对象 MqttApplicationMessage,最直接的⽅法是使⽤其实构造函数,
传⼊主题、内容、Qos 等参数。
mqttClient.SubscribeAsync(new List<TopicFilter> {
new TopicFilter("家/客厅/空调/#", MqttQualityOfServiceLevel.AtMostOnce)
});
吸血鬼日记klaus得到 MqttApplicationMessage 消息对象后,通过客户端对象调⽤其 PublishAsync 异步⽅法进⾏消息发布。
mqttClient.PublishAsync(appMsg);
6 跟踪消息
MQTTnet 提供了⼀个静态类 MqttNetTrace 来对消息进⾏跟踪,该类可⽤于服务端和客户端。MqttNetTrace 的事
cintra
件TraceMessagePublished ⽤于跟踪服务端和客户端应⽤的⽇志消息,⽐如启动、停⽌、⼼跳、消息订阅和发布等。事件参
数MqttNetTraceMessagePublishedEventArgs 包含了线程ID ThreadId、来源 Source、⽇志级别 Level、⽇志消息 Message、异常信
息 Exception 等。
MqttNetTrace.TraceMessagePublished += MqttNetTrace_TraceMessagePublished;
spankwireprivate static void MqttNetTrace_TraceMessagePublished(object nder, MqttNetTraceMessagePublishedEventArgs e)
{
Console.WriteLine($">> 线程ID:{e.ThreadId} 来源:{e.Source} 跟踪级别:{e.Level} 消息: {e.Message}");
if (e.Exception != null)
{
Console.WriteLine(e.Exception);
}
}
同时 MqttNetTrace 类还提供了4个不同消息等级的静态⽅法,Verbo、Information、Warning 和 Error,⽤于给出不同级别的⽇志消息,该消息将会在 TraceMessagePublished 事件中输出,你可以使⽤ e.Level 进⾏过虑。
7 运⾏效果
以下分别是服务端、客户端1和客户端2的运⾏效果,其中客户端1和客户端2只是同⼀个项⽬运⾏了两个实例。客户端1⽤于订阅传感器的“温度”数据,并模拟上位机(如 APP 等)发送开关控制命令;客户端2订阅上位机传来的“开关”控制命令,并模拟温度传感器上报温度数据。
7.1 服务端
7.2 客户端1