MQTT详解以及在IoT中的应用
MQTT定义:
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分。该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器和制动器的通信协议。
MQTT简介:
MQTT是基于客户端/服务器的二进制的发布、订阅编程模式的消息协议,由于规范简单,非常适用于带宽低,低功耗的iot场景,比如:遥感、M2M、智慧城市、智能家居、医疗医护等。由于物联网的环境非常的特别,所以MQTT有他的设计规范:
- 精简,不添加可有可无的功能
- 发布、订阅模式,方便消息在传感器之间传递
- 允许用户动态创建主题,零运维成本
- 把传输量降到最低提高传输效率
- 考虑地带宽、高延迟、不稳定的网络因素
- 充分理解客户端羸弱的计算能力
- 支持连续会话
- 提供服务质量管理。(Qos:至少一次、至多一次、只有一次)
- 假设数据不可知,不强求数据的类型和格式,保持灵活性
mqtt发布订阅模式:
和传统的http的请求/应答模式不一样(request/response),发布订阅模式解耦了发布者和订阅者之间的关系,这意味着发布者和订阅者不需要直接联系,由代理进行转发,什么意思呢?打个比方你打电话给你的女朋友翟小树,需要等翟小树接听电话之后你们才可以交流,这个就是http的请求响应模式,试想你是一个大明星,胡大橙和翟小树都关注了你的微博,当你发布一条微博的时候,微博服务器就是转发给他们两个的好友动态,此时你就是发布者(publisher),他们就是订阅者(subscribe),就这事典型的异步发布订阅模式。发布订阅模式带来了一些好处:
- 发布者和订阅者不必彼此了解,多个订阅者之间也不需要彼此了解,只需要认识同一个消息代理
- 发布者和订阅者不需要同时在线
- 发布者和订阅者不需要进行任何的交互
为了满足不同的场景,mqtt支持三种不同的服务质量(Qos)
- 最多一次 (基于tcp/ip,发布者会想尽办法发布,但是遇到意外不会重试,使用场景比如传感器上报数据某次丢失但是过几秒就会另一次上报,对数据的要求不是那么的精确就可以设置这种)
- 至少一次 (如果订阅者没有收到,发布者会重复的发送,确保消息达到,但是这种会存在一种问题就是重复的接收消息)
- 只有一次(缺点是减少了并发或者增加了延时,但是如果消息重复或者丢失都不可接收的时候,这种最合适)。
MQTT协议原理:
实现mqtt协议需要客户端和服务端,这个流程有三个角色,发布者(publish)、订阅者(subscribe)、代理,其中发布者可以是某个topic的发布者,也可以是另一个topic的订阅者。
mqtt的消息分为两个部分:主题(topic)、负载(payload)。
- topic:消息的类型,订阅者订阅了该消息之后就会收到代理转发的消息。
- payload:消息的内容。
MQTT客户端:
- 发布订阅者可能订阅的消息
- 订阅其他客户端可能发布的消息
- 退订或删除应用程序的消息
- 断开与服务器的连接
MQTT服务端:
- 接收来自客户端的连接
- 接收客户端发布的消息
- 转发订阅对应topic的消息给订阅者
- 处理来自客户端的订阅和退订请求
MQTT协议中的一些方法:
- connect:与服务端进行连接
- disconnect 等客户端完成所有工作后断开与服务器的tcp/ip连接
- publish 客户端发布消息
- subscribe 客户端订阅主题(异步过程)
- unsubscribe 等待服务器取消客户端的一个或多个订阅的topic(异步过程)
MQTT在IoT中的实践
这是一张典型的MQTT在IoT中的应用,其中app作为客户端,智能网关也作为客户端(实际上在我们公司的V6云平台也是作为客户端),物联网云服务作为统一的服务端负责收发,app和V6云订阅同一个主题,app和网关订阅另一个主题,当每次需要发送mqtt命令时首先判断是账号登录(V6云)还是网关登录,于此publish对应的topic和payload,物联网云服务收到mqtt消息后转发给订阅同一个topic主题的客户端(V6云或者网关),然后通过再由网关发送对应的指令去控制低功耗设备(比如门锁的开关,灯泡的开关)。这个时候可以看出topic的重要性,合理的定义topic可以实现不同业务功能。先说一下我们公司的topic的定义,由于初期没有考虑周到,只是针对V6云和网关定义了两个不同的topic,导致后面有一项业务功能是给分享的账号发一些mqtt消息时导致V6云需要做大量的过滤,完全没有体现出topic的优势,接下来先讲一下topic主题设计。
Topic主题设计
主题层级分隔符:“/” 主题层级分隔符是的主题十分结构化
- china/jiangsu/nanjing
- shanghuang/xiadayu
- shanghuang/huxiangli/81hao
多层通配符:"#’ 是用于匹配主题中任意层级的通配符。多层通配符表示它的父级和任意数量的子层级。多层通配符必须位于它自己的层级或者跟在主题层级分隔符后面。不管哪种情况,它都必须是主题过滤器的最后一个字符 .比如你订阅了一个jiangsu/nanjing/*,你会收到如下的主题的消息
- jiangsu/nanjing
- jiangsu/nanjing/jiangning
- jiangsu/nanjing/qixia/nanjingdaxue
定阅主题示例
- jiangsu/# //也单独匹配“江苏”,因为#包括他的父级。
- # //有效,会收到所有的topic的消息
- jiangsu/nanjing/* //有效
- jiangsu/nanjing* //无效
- jiangsu/#/nanjing //无效,必须是主题过滤器的最后一个字符
单层通配符 “+” 只能用于单个层级匹配的通配符,在主题过滤器的任意层级都可以使用单层通配符,包括第一个和最后一个层级。然而它必须占据过滤器的整个层级 。可以在主题过滤器中的多个层级中使用它,也可以和多层通配符起使用。举个栗子:
- china/+ 只能匹配china/jiangsu
- china/+/+/zhaixiaoshu 可以匹配 china/xianlin/nanda/zhaixiaoshu 或者china/shanghuang/xiadayu/zhaixiaoshu
总结一下
- 所有的主题名和主题过滤器必须至少包含一个字符
- 主题名或主题过滤器以前置或后置斜杠 “/” 区分
- 只包含斜杠 “/” 的主题名或主题过滤器是合法的
- 主题名和主题过滤器是 UTF-8 编码字符串, 它们不能超过 65535 字节
- 主题名和主题过滤器是区分大小写的
从上可以看出合理的topic订阅能够实现花样的功能,就比如当初设计分享的用户的时候完全可以用通配符去设计,可以大大的减小计算和筛选量。