一、概述
MQTT(Message Queuing Telemetyr Transport 消息队列遥测传输协议):基于发布/订阅(Publish/Subscribe)模式的轻量级通讯协议,该协议构建于TCP/IP协议之上。
MQTT运行于TCP之上,属于应用层协议。
每条MQTT命令消息的消息头都包含一个固定的报头,有些消息会携带一个可变报文头和一个负荷。消息格式如下:
固定报文头|可变报文头|负荷
最少有两个字节,第一个字节包含消息的类型(Message Type)和QoS级别等标志位。第二个字节开始是剩余长度字节,该长度是后面的可变报文头加消息负载的总长度,该字段最多允许四个字节。
剩余长度字段单个字节的最大值为0x7F. 也就是127个字节。MQTT协议规定,单个字节的最高位如果是1,表示后续还有字节存在,第八位起延续位的作用。
由于MQTT协议最多使用四个字节表示剩余长度,并且最后一个字节的最大值只能是0x7F,而不是0xFF。所以能发送的最大消息长度是256MB,而不是512MB。
主要包含协议名,协议版本,连接标志,心跳间隔时间,连接返回码,主题名等。
实际上可以理解为消息的主体。当MQTT发送的消息类型是CONNECT(连接)、PUBLISH(发布)、SUBSCRIBE(订阅)、SUBACK(订阅确认)、UBSUNSCRIBE(取消订阅)时会带有负荷。
固定报文头中的第一个字节包含连接标志,连接标志用来区分MQTT的消息类型。MQTT协议拥有14中不同的消息类型。如下图:
可简单分为连接及终止、发布和订阅、Qos2消息的机制以及各种确认ACK。
MQTT消息质量有三个等级,QoS 0、Qos 1、Qos 2。
Qos 0:最多分发一次,消息的传递完全依赖底层的TCP/IP网络,协议里没有定义应答和重试。消息只会到达服务端一次,要么就没到达。
Qos 1:至少分发一次、服务器的消息接收由PUBACK消息进行确认,如果通信链路或设备异常,或指定时间内没有收到确认消息,发送端会重发这条在消息头中设置了Dup位的消息。
Qos 2:只分发一次。最高级别的消息传递,消息丢失和重复都是不可接受的,使用这个服务质量等级会有额外的开销。
在可变报文头的连接标志位字段(Connect Flags)里面有三个will标志位:Will Flag Will Qos和Retain Flag。这些will字段用于监控客户端与服务器之间的连接状况。
遗愿消息:服务器与客户端通信时,当遇到异常或客户端心跳超时的情况,MQTT服务器会替客户端发布一个will消息。当然如果服务器收到来自客户端的DISCONNECT消息则不会触发wiwll消息的发送。因此will字段可以应用于设备掉线后通知用户的场景
MQTT客户端可以设置一个心跳间隔时间(keep Alive Timer),表示在每个心跳检测时间内发送一条消息。如果在这个时间周期内,没有业务数据相关的消息,客户端会发送一个PINGREQ消息,相应的,服务器会返回一个PINGRESP消息进行确认。
如果服务器在一个半(1.5)个心跳间隔时间周期内没有收到来自客户端的消息,就会断开与客户端的连接。心跳间隔时间最大值可以设置为18个小时,8表示客户端不会断开。
发布/订阅模式解耦了发布消息的客户(发布者)和订阅消息的客户(订阅者)之间的关系。发布者与订阅者并不需要直接建立联系。
这个模式的好处有:
1) 发布者与订阅者只需要知道同一个消息代理即可。
2) 发布者与订阅者不需要直接交互,不需要同时在线。
MQTT基于二进制而不是字符串。固定报文头仅有两个字节,相比于其他协议(HTTPS 和XMPP都是基于字符串实现,有冗长的头部),发送一条消息更省流量
由于MQTT运行于TCP层之上并且以明文传输,可以使用Wireshark看到MQTT发送的所有消息,消息指令一览无遗。这会带来一定的风险:
1) 设备可能会被盗用
2) 客户端和服务端的静态数据可能是可访问的(可能会被修改)
3) 协议行为可能有副作用(如计时器攻击)
4) 拒绝服务攻击
5) 通信可能会被拦截 修改 重定向或者泄露
6) 虚假控制报文注入
作为传输协议,MQTT只关注消息传输,提供安全功能是开发者的责任。
支持两种层次的认证
1) 应用层:MQTT支持客户标识,用户名和密码认证
客户标识:MQTT客户端可以发送最多65535个字符作为客户标识,一般来说可以使用嵌入式芯片的MAC地址或芯片序列号。
用户名和密码:支持通过CONNECT消息的USERNAME和password字段发送用户名和密码。但是由于是用的明文传输,抓包工具很容易就获取。
2) 传输层:传输层可以使用TLS,除了加密通讯,还可以使用X509证书来认证设备。
在传输层认证是这样的:MQTT代理在TLS握手成功之后可以继续发送客户端的X509证书来认证设备,如果设备不合法就中断连接。
MQTT协议只实现了传送消息的格式,并没有限制用户协议需要按照特定风格。因此在MQTT协议之上,我们需要定义一套自己的通信协议。就可以有下面几种选择了、
失去了可读性,可以将流量控制的比较小。单片开发可能会比较喜欢用这个。
这个会方便阅读。对于高级语言开发者来说,字符串依旧不是最佳选择。键值对(Key-value)才是最优形式。
在这门语言中,一切都是对象。因此任何支持的类型都可以通过JSON来表示。例如字符串、数字、对象、数组等、
语法规则是:对象表示键值对、数据用逗号分开、花括号保存对象、方括号保存数组。
JSON层次结构简洁清晰,便于阅读和编写,易于机器解析和生成,有效提升网络传输效率。
综上,MQTT+JSON是最优解。
MQTT基于异步发布/订阅的实现解耦了消息发布者和订阅者,基于二进制的实现节省了存储空间及流量,同时拥有更好的消息处理机制。
MQTT协议是为大量计算能力有限,且工作在低带宽、不可靠的网络的远程传感器和控制设备通讯而设计的协议
以上 参考IoT -- (七)MQTT协议详解_精品博客-CSDN博客_mqtt协议
参考:MQTT协议-MQTT协议解析(MQTT数据包结构) - 章鱼哥哥 - 博客园
补充几个概念:
参考:https://www.jianshu.com/p/ecde412d2eeb
MQTT 客户端
一个使用 MQTT 协议的设备、应用程序等,它总是建立到服务器的网络连接。
可以发布信息,其他客户端可以订阅该信息
订阅其它客户端发布的消息
退订或删除应用程序的消息
断开与服务器连接
MQTT 服务器
MQTT 服务器以称为 Broker(消息代理),以是一个应用程序或一台设备。它是位于消息发布者 和订阅者之间
主题(Topic)
连接到一个应用程序消息的标签,该标签与服务器的订阅相匹配。服务器会将消息发送给订阅所匹配标签的每个客户端。
要订阅的主题。一个主题可以有多个级别,级别之间用斜杠字符分隔。例如,/world
和 emq/emqtt/emqx
是有效的主题。
订阅者的Topic name支持通配符#和+ :
客户端成功订阅某个主题后,代理会返回一条 SUBACK 消息,其中包含一个或多个 returnCode 参数
主题筛选器(Topic Filter)
一个对主题名通配符筛选器,在订阅表达式中使用,表示订阅所匹配到的多个主题。
QoS(消息传递的服务质量水平)
服务质量,标志表明此主题范围内的消息传送到客户端所需的一致程度。
会话(Session)
每个客户端与服务器建立连接后就是一个会话,客户端和服务器之间有状态交互。会话存在于一个网络之间,也可能在客户端和服务器之间跨越多个连续的网络连接。
订阅(Subscription)
订阅包含主题筛选器(Topic Filter)和最大服务质量(QoS)。订阅会与一个会话(Session)关联。一个会话可以包含多个订阅。每一个会话中的每个订阅都有一个不同的主题筛选器。
发布(publish)
控制报文是指从客户端向服务端或者服务端向客户端传输一个应用消息,MQTT 客户端发送消息请求,发送完成后返回应用程序线程
负载(Payload)
消息订阅者所具体接收的内容