前言

  • .Net Core 3.1 WebApi
  • 列出了mqtt客户端的封装目的是为了了解运作机制

1、封装mqtt客户端

  • mqtt底层协议基于MQTTnet 版本2.8.5 github地址
  • 实例化【单例注入AOC】
  • 发布消息
  • 订阅消息

实例化

public MqttNetClient(MqttConfig _mqttConfig, EventHandler<MqttApplicationMessageReceivedEventArgs> receivedMessageHanddler,
ICache iCache)
{
mqttConfig = _mqttConfig;
_iCache=iCache;
var factory = new MqttFactory();
mqttClient = factory.CreateMqttClient() as MqttClient;
clientId = "MQTT:Cloud:Client:" + _mqttConfig.ClientIdPre + ":" + Guid.NewGuid();
//实例化一个MqttClientOptionsBulider
options = new MqttClientOptionsBuilder()
.WithTcpServer(_mqttConfig.Server, _mqttConfig.Port)
.WithCredentials(_mqttConfig.Username, _mqttConfig.Password)
.WithClientId(clientId)
.Build();
if (receivedMessageHanddler != null)
{
//是服务器接收到消息时触发的事件,可用来响应特定消息
mqttClient.ApplicationMessageReceived +=receivedMessageHanddler;
}
//是客户端连接成功时触发的事件
mqttClient.Connected+=Connected;
//是客户端断开连接时触发的事件
mqttClient.Disconnected+=Disconnected;
//连接服务器
mqttClient.ConnectAsync(options);
}

发布消息

public async Task PublishAsync(string topic, string content)
{
var message = new MqttApplicationMessageBuilder();
message.WithTopic(topic);
message.WithPayload(content);
message.WithAtMostOnceQoS();
message.WithRetainFlag(false);
await mqttClient.PublishAsync(message.Build());
}

订阅消息

public async Task SubscribeAsync(string topic)
{
await mqttClient.SubscribeAsync(topic);
}

监听mqtt回复消息

随WebApi应用自启动单例MqttClient去消费消息

  • 初始化mqtt连接配置
  • 主动订阅Topic
  • 消费mqtt消息handler

初始化mqtt连接配置&主动订阅Topic代码

var mqttConfig = new MqttConfig
{
Server = _config.Get("EMQServer"),//服务器IP
Port = int.Parse(_config.Get("EMQPort")),//端口
ClientIdPre = "IoT.MQTT"//IoT MQTT连接
}; mqttConfig.TopicList = new List<string>()
{
IoTSubscribeMqttTopicEnum.主动订阅.GetEnumDescription()
};
_mqttNetClient = new MqttNetClient(mqttConfig, ReceivedMessageHandler, _cache);

消费mqtt消息handler

public static void ReceivedMessageHandler(object sender, MqttApplicationMessageReceivedEventArgs e)
{
var topic = e.ApplicationMessage.Topic;
var payload = EncryptUtil.Base64Decode(Encoding.UTF8.GetString(e.ApplicationMessage.Payload)); //如果Topic是主动订阅,则去订阅http接口入参传过来的回复Topic字段
if (topic.Equals(IoTSubscribeMqttTopicEnum.主动订阅.GetEnumDescription()))
{
_mqttNetClient.SubscribeAsync(payload);
}
else
{
var mqttPayloadModel = JsonConvert.DeserializeObject<MqttPayloadModel<MqttContentModel>>(payload);
//插入缓存是为了在回复的时候用,通过MID保持一致
var cacheKey = $"{RedisKeyEnum.MQTT接收消息.GetEnumDescription()}:{mqttPayloadModel.Con.Mid}";
var _cache = _serviceProvider.GetService<ICache>();
_cache.InsertAsync(cacheKey, payload, 5 * 60);
}
}

2、封装http接口

发布消息代码

public async Task<BaseOutModel<PublishMessageOutModel>> PublishMessage(PublishMessageInModel publishInModel)
{
//如果回复Topic不为空,则需要等待mqtt返回消息,通过MID来保持一致
if (!String.IsNullOrEmpty(publishInModel.ReceiveTopic))
{
//先主动订阅
_mqttNetClient.PublishMessageAsync(IoTSubscribeMqttTopicEnum.主动订阅.GetEnumDescription(), EncryptUtil.Base64Encode(publishInModel.ReceiveTopic));
//发布消息
_mqttNetClient.PublishMessageAsync(publishInModel.Topic, publishInModel.Content);
var messageId= JsonConvert.DeserializeObject<MqttPayloadModel<MqttContentModel>>(EncryptUtil.Base64Decode(publishInModel.Content)).Con.Mid;
var cacheKey = $"{RedisKeyEnum.MQTT接收消息.GetEnumDescription()}:{messageId}";
//8秒为超时
var endTime = DateTime.Now.AddSeconds(8);
var received = false; var cacheMsg = String.Empty;
while (!received)
{
cacheMsg = await _cache.GetAsync<String>(cacheKey);
if (cacheMsg != null || DateTime.Now > endTime)
{
received = true;
}
}
//缓存不为空,代表收到了mqtt客户端的响应
if (cacheMsg != null)
{
//移除回复消息缓存
_cache.RemoveAsync(cacheKey);
return new BaseOutModel<PublishMessageOutModel>
{
Message = "发布消息成功,接收消息成功",
Data = new PublishMessageOutModel { Content = cacheMsg, ReceiveStatus = MqttReceiveStatusEnum.Yes.IntToEnum() }
};
}
return new BaseOutModel<PublishMessageOutModel>
{
Message = "发布消息成功,接收消息失败",
Data = new PublishMessageOutModel { ReceiveStatus = MqttReceiveStatusEnum.No.IntToEnum() }
};
}
//如果Topic为空,则只需要发布消息就好
await _mqttNetClient.PublishMessageAsync(publishInModel.Topic, publishInModel.Content);
return new BaseOutModel<PublishMessageOutModel> { Message = "发布消息成功",Data=new PublishMessageOutModel { } };
}

接口请求入参

参数名 必选 类型 说明
Topic string 发布的Topic
Content string 发布的消息体,需要Base64字符串
ReceiveTopic string 接收消息Topic【只有不为空,才会去处理接收设备端mqtt的回复消息】
DeviceSn string 设备编号

接口请求出参

参数名 类型 说明
Data - Content string 回复消息的内容
Data - ReceiveStatus integer 回复状态【1 已回复,0 未回复 即超时】
Code integer 返回状态码【200正常,0有错误】
Message string 错误描述,Code为0使用

接口请求示例

1、在Startup中将HttpClient注入IOC

services.AddHttpClient("iotmqtt", x =>
{
x.BaseAddress= new Uri("http://iotmqtt.liyunzhi.com");
});

2、调用

//请求mqtt的消息体
var content = new
{
Met = "Reboot",
Con = new
{
Mid = Mid,
Ts = Ts,
Sign = Sign,
Cid = Cid
}
}; //请求入参模型
var iotPublishMessageModel = new
{
//请求Topic
Topic = "Device/Reboot",
//请求mqtt的消息体
Content = EncryptUtil.Base64Encode(JsonConvert.SerializeObject(content)),
//消息ID
MessageId = Mid,
//可选参数 需要消息回复则传
ReceiveTopic = Mid+"Device/Reboot",
//设备号
DeviceSn = "123123123"
}; //
var client = _httpClientFactory.CreateClient("iotmqtt");
var httpResponseMessage = client.PostAsJsonAsync("Api/PublishMessage", iotPublishMessageModel).Result;
//如果当前方法用async异步修饰,请不要.Result 请await
//var httpResponseMessage =await client.PostAsJsonAsync("Api/PublishMessage", iotPublishMessageModel);
if (httpResponseMessage.IsSuccessStatusCode)
{
//成功,返回内容自己自行解析,解析参考接口请求出参
var data= httpResponseMessage.Content.ReadAsStringAsync().Result;
//如果当前方法用async异步修饰,请不要.Result 请await
//var data= await httpResponseMessage.Content.ReadAsStringAsync();
}
else
{
//这里是失败的代码了,即发送失败了
}

3、Github开源地址

http接口封装mqtt协议的更多相关文章

  1. Android实现推送方式解决方案 - 长连接+心跳机制(MQTT协议)

    本文介绍在Android中实现推送方式的基础知识及相关解决方案.推送功能在手机开发中应用的场景是越来起来了,不说别的,就我们手机上的新闻客户端就时不j时的推送过来新的消息,很方便的阅读最新的新闻信息. ...

  2. 物联网项目开发必读 深度分析MQTT协议优缺点

    物联网并不仅仅是一种网络,而是一个新的生态环境,它描述的本质是越来越多的使用物品通过网络连接在一起并可使用单个或者多个的终端设备对它们进行各种控制和使用—当然,工业上的物联网通常连接到的石鼓传感器或者 ...

  3. 消息中间件技术 - 浅谈mqtt协议及其实现

    作者:carter(佘虎),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 1.1概念 MQTT(MQ Telemetry ...

  4. MQTT 协议学习:008-在STM32上移植MQTT

    前言 通过前面了解MQTT有关概念.分析了有关的报文,我们对于这个协议也有了更深的认识.但纸上谈来终觉浅,绝知此事要躬行. 本文参考:<STM32+W5500+MQTT+Android实现远程数 ...

  5. Java微信公众平台接口封装源码分享

    前言:      这篇博客是在三月初动手项目的时候准备写的,但是为了完成项目只好拖延时间写这篇博客,顺便也可以在项目中应用我自己总结的的一些经验.今天看来,这些方法的应用还是可以的,至少实现了我之前的 ...

  6. 基于MQTT协议进行应用开发

    官方协议有句如下的话来形容MQTT的设计思想: "It is designed for connections with remote locations where a "sma ...

  7. 转:XMPP协议、MQTT协议、HTTP协议、CoAP协议的基本比较

    一.先看下相关国外的专业数据对四大协议的比较: Protocol                                    CoAP                         XMP ...

  8. Lua编写wireshark插件初探——解析Websocket上的MQTT协议

    一.背景 最近在做物联网流量分析时发现, App在使用MQTT协议时往往通过SSL+WebSocket+MQTT这种方式与服务器通信,在使用SSL中间人截获数据后,Wireshark不能自动解析出MQ ...

  9. Python 基于urllib.request封装http协议类

    基于urllib.request封装http协议类 by:授客QQ:1033553122 测试环境: Python版本:Python 3.3   代码实践 #!/usr/bin/env python ...

随机推荐

  1. Java并发编程实践

    最近阅读了<Java并发编程实践>这本书,总结了一下几个相关的知识点. 线程安全 当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任 ...

  2. Atlassian Confluence 5.1.2 破解版部署

    Atlassian Confluence(简称Confluence)是一个专业的wiki程序.它是一个知识管理的工具,通过它可以实现团队成员之间的协作和知识共享.Confluence 不是一个开源软件 ...

  3. elementUI form表单验证不通过的原因

    <el-form :model="form" :rules="rules"> <el-form-item prop="input&q ...

  4. 题解 洛谷 P6349 【[PA2011]Kangaroos】

    先考虑对题目进行转化,我们称两个区间有交集为这两个区间能匹配,每个询问就是在序列中最长能连续匹配的长度. 对序列中的一个区间\([l,r]\)和询问的一个区间\([L,R]\),若满足\(L \leq ...

  5. asp.net core appsetting.json 绑定读取

    appsettings.json中,具有: "AppSettings": { "AzureConnectionKey": "***", &q ...

  6. Asp.NetCore3.1 WebApi 使用Jwt 授权认证使用

    1:导入NuGet包 Microsoft.AspNetCore.Authentication.JwtBearer 2:配置 jwt相关信息 3:在 startUp中 public void Confi ...

  7. 如何消灭飞机的“黑色十分钟”,AI来帮忙

    近年来,“AI的应用和落地”逐渐成了具化的关键词,它和很多事物很多行业结合在一起,形成了奇妙的“化学反应”.例如,在日常生活中,AI可以推送我们喜欢的新闻或视频,可以在拍照的时候识别场景提升照片的美感 ...

  8. apache 基本配置

    1.1 ServerRoot 配置 [ServerRoot "" 主要用于指定Apache的安装路径,此选项参数值在安装Apache时系统会自动把Apache的路径写入.Windo ...

  9. state实例

    States是SaltStack中的配置语言,在日常进行配置管理时需要编写大量的States文件. 比如我们需要安装一个包,然后管理一个配置文件,最后保证某个服务正常运行. 这里就需要我们编写一些st ...

  10. 使用Faker库生成模拟数据

    一.相关文档 该库在laravel框架中默认已经存在,无需手动进行安装.使用参考文档: https://packagist.org/packages/fzaninotto/faker 二.简单示例 & ...