MQTT协议学习笔记

Posted Shi Peng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MQTT协议学习笔记相关的知识,希望对你有一定的参考价值。

一、MQTT协议概述

MQTT(Message Queueing Telemetry Transport,消息队列遥测传输协议):是一种基于 发布/订阅 模式的轻量级通讯协议。

MQTT协议最大的优点:可以以极少的代码和有限的带宽,为远程设备提供实时可靠的消息服务。

MQTT协议作为一种低开销、低带宽占用的即时通信协议,在物联网、小型设备、移动应用等方面有广泛的应用。

在物联网开发中,除了MQTT,还有XMPP和CoAP协议等,后面做对比。

总结:MQTT消息小(传输快省带宽),并传输可靠。

二、MQTT详解

2.1、MQTT协议属于哪一层协议

MQTT位于应用层。只要是支持TCP/IP协议栈的地方,就可以使用MQTT。

详解:TCP/IP参考模型分4层:应用层、传输层、网络层、链路层。其中TCP和UDP位于传输层,而HTTP、FTP、SSH等位于应用层。所以MQTT运行在TCP协议的上层,即应用层。

2.2、MQTT的消息格式

每条MQTT消息,都包含一个固定的报文头(Fixed Header),有些消息会携带一个可变的报文头(Variable Header)和一个负荷(Payload)

消息格式如下:

固定报文头 | 可变报文头 | 负荷

2.2.1、固定报文头(Fixed Header)

MQTT的固定报文头最少有两个字节(可能大于2个字节):
1)第一个字节是消息类型(Message Type)和QoS级别等标识位。
2)第二个字节开始是剩余长度字段,该长度是后面的 ”可变报头+消息负载“ 的总长度,该长度最多允许4个字节。

MQTT协议最多只允许4个字节表示剩余长度,且最后一个字节的第8位起到”延续位“作用,1表示后面还有字节存在,所以最大消息长度为256MB,而不是512MB。

2.2.2、可变报文头(Variable Header)

可变报文头包括:
1)协议名
2)协议版本
3)连接标志(Connect Flags)
4)心跳间隔时间(Keep Alive timer)
5)连接返回码(Connect Return Code)
6)主题名(Topic Name)

2.2.3、有效符合(Payload)

有效符合其实就是消息主体(message body)

当MQTT发送消息的类型为下面类型时,则会带有消息主体:
1)CONNECT:连接
2)PUBLISH:发布
3)SUBSCRIBE:订阅
4)SUBACK:订阅确认
5)UNSUBSCRIBE:取消订阅

2.3、MQTT协议的主要特性

2.3.1、MQTT的消息类型(Message Type)

在 “固定报文头” 中的第一个字节,包含 “连接标志(Connect Flag)”,用来区分MQTT的消息类型。

MQTT拥有14种不同的消息类型,如下表:
在这里插入图片描述
这14种消息类型,可以简单地分为:
1)连接及断开连接
2)发布及订阅
3)QoS 2消息的机制
4)各种确认ACK

2.3.2、消息质量(QoS)

MQTT的消息质量,分三个等级:最多一次、至少一次、正好一次。

1)QoS 0 :最多一次。只发一次,不管是否到达。
2)QoS 1 :至少一次。服务器接收消息,通过PUBACK确认,如指定时间为收到确认,则发送端重发(此时该消息在消息头设置了DUP位)
3)QoS 2 :正好一次。消息丢失或重复都不可接受。这个质量等级会有额外的开销。

QoS 0 ~ 2 等级的应用,用共享单车举例:
1)QoS 0 最多一次:智能锁定时发送共享单车位置,一次失败了没关系,过段时间还会再次发送
2)QoS 1 至少一次:开锁
3)QoS 2 正好一次:骑车完付钱

2.3.3、遗愿标志(Will Flag)

在可变报头的连接标志位字段(Connect Flag)里有三个Will标志位:
1)Will Flag
2)Will QoS
3)Will Retain Flag
这些Will字段用于监控客户端与服务器之间的连接状况。如果设置了Will Flag, 则必须设置Will QoS和Will Retain,消息主体中也必须有Will Topic和Will Message字段。

遗愿消息是怎么回事呢?当客户端与服务端通信时,当遇到异常或客户端心跳超时时,MQTT服务器会替客户端发一个Will消息。
当如果服务器收到来自客户端的DISCONNECT消息,则不会触发Will消息的发送。

因此,Will字段应用于设备掉线后,需要通知用户的场景。

2.3.4、连接保活机制(Keep Alive Timer)

MQTT客户端可以设置一个心跳间隔时间(Keep Alive Timer),表示在每个心跳时间内发送一条消息。如果在这个时间周期内,没有业务数据相关的消息,客户端会发一个PINGREQ消息,相应的,服务器会返回一个PINGRESP消息进行确认。如果服务器在一个半(1.5)心跳周期内没有收到来自客户端的消息,就会断开与客户端的连接。心跳间隔时间最大值大约可以设为18个小时,0值意味着客户端不断开。

2.4、MQTT协议的其他特性

2.4.1、异步 发布/订阅 实现

sub/pub模式,解耦了消息的发布者和订阅者,他们不需要直接交互,而是通过消息代理, 他们也不需要同时在线。

由于实现了sub/pub模式,MQTT可以实现双向通信:即服务端也可以向broker发消息,然后客户端来订阅。

2.4.2、二进制格式 实现

MQTT协议基于二进制,而不是字符串(比如HTTP和XMPP都是基于字符串实现:HTTP和XMPP都有冗长的协议头部,而MQTT固定报文头仅有两字节,所以相比其他协议,发送一条消息最省流量)。

2.5、MQTT协议的 安全

MQTT运行于TCP的上层应用层,并以明文传输(这相当于HTTP的明文传输),通过wireshark可以抓包的MQTT发送的消息:
在这里插入图片描述
这样存在以下风险:
1)拒绝服务攻击
2)通信可能被拦截、篡改、重定向或信息泄露

MQTT作为传输协议,仅关注消息传输,提供安全性是开发者的责任。安全性可从以下三个层次来考虑:

1)应用层:MQTT提供了客户标识(Client Identifier)及用户名和密码,可在应用层验证设备。

<1> 客户标识:
客户端最多可以发送65535个字符作为客户标识(Client Identifier),可以嵌入芯片的mac地址或芯片序列号。
虽然用户标识不一定可靠,但在某些封闭环境也够了。

<2> 用户名和密码:
MQTT协议支持通过CONNECT消息的username和password字段发送用户名和密码。

但用户名和密码也是明文的,可以通过抓包工具抓到。

一般来说,通过用户标识、用户名和密码已经够了,如果不够,可在传输层进行认证。

2)传输层:类似于HTTPS,MQTT基于TCP连接,也可以加上一层TLS,传输层使用TLS加密是确保安全的一个好手段,可以防止中间人攻击。客户端证书不但可以作为设备的身份凭证,也可以用来验证设备。

MQTT代理在跟客户端通过TLS握手成功后,向客户端发送客户端的X509证书来认证设备,如果发现设备不合法,则中断连接。

采用x509认证的好处是,在传输层就可以验证设备的合法性,这样在发送CONNECT之前就可以阻隔非法设备连接,以节省不必要的资源浪费。

3)网络层:如果有条件的话,可以通过拉专线,或使用VPN来连接设备与MQTT代理。(这在公网是不可能实现的)

2.6、选择用户数据格式

MQTT协议只是想了传送消息的格式,并没有限制用户协议需要按照一定的风格。因此,在MQTT协议之上,我们需要定义一套自己的通信协议:比如,发布者向设备发布一条打开消息,设备可以回复一个消息并携带返回码,这样的消息格式是使用二进制、字符串还是JSON格式呢?

2.6.1、二进制

MQTT协议原本就是基于二进制的,所以用户协议使用二进制是个不错的选择。虽然二进制可读性差,但流量非常小。

2.6.2、字符串

对于单片机开发者来说,字符串也是一个选择,比如通过串口传输的AT指令,就是基于字符串通信的。字符串的优点是可读性好,对于高级语言来说,KV方式可读性更好。

2.6.3、JSON

JSON格式比字符串更易于阅读,且易于机器的生成和解析。

三、怎样使用MQTT协议

3.1、通过BAT的公有云平台

目前百度、阿里、腾讯的云平台都支持,如OneNET云平台、云巴等。

3.2、自建MQTT服务器

如果不想使用云平台,只想自己玩一些MQTT,那么可以:
1)Apache-Apollo:一个代理服务器,在ActiveMQ基础上发展起来,可支持STOMP、AMQP、MQTT、Openwire、SSL、WebSocket等多种协议。

2)EMQ:好处百万级开源MQTT消息服务器,基于Erlang/OTP语言开发,支持大规模连接和分布式集群,发布定于模式的开源MQTT消息服务器。

3)HiveMQ:一个企业级MQTT代理,主要用于企业和新兴集群到集群M2M通信和内部传输。

4)Mosquitto:一款实现了消息推送协议MQTT v3.1 的开源消息代理软件,提供轻量级的、支持可发布、订阅的消息推送模式。-- 爱奇艺就是基于这个搞的,所以只支持推。

四、MQTT的调试工具

MQTT的调试工具,可以考虑使用HiveMQ的MQTT客户端–HiveMQ Websockets Client,这是基于WebSocket的浏览器mqtt客户端,支持主题订阅和发布。

五、MQTT协议的优势

5.1、MQTT vs TCP Socket:MQTT好在解决了分包、粘包的问题

MQTT运行在TCP层之上,其实没有可比性,但还是要比较下:
由于TCP有粘包、分包问题,所以传输数据 时,需要自定义协议,如传输的数据报超过了最大报文段程度,一定要给协议定义一个消息长度字段,确保接收端能通过缓冲,完整收取消息。一个简单的协议定义:消息头部+消息长度+消息正文。

但使用MQTT则无需考虑这个问题,这些MQTT都已经处理好了,MQTT最长可以一次性发送256MB数据,不用考虑粘包、分包的问题。

5.2、MQTT vs HTTP:HTTP协议太冗余,MQTT小

要实现服务端向客户端发消息的反向技术,就需要用到Comet技术,Comet是基于HTTP的长连接“服务器推”技术,主要用两种实现模型:
1)基于Ajax的长轮询方式
2)基于iframe及httpfile的流(straming)方式。

Comet技术由于需要不断的请求服务器,会导致通信开销非常大,假设HTTP冗余的报文头,在流量上比较费。

MQTT更节省流量。

5.3、MQTT vs XMPP:MQTT是二进制,XMPP是文本

MQTT最大的竞争者是XMPP。XMPP(可扩展通讯与表示协议)是一项用于实时通信的开放技术,它使用XML作为交换信息的格式。其优点是成熟、强大、可扩展性强。目前主要应用于许多聊天系统,在消息推送领域,MQTT和XMPP互相竞争。

下面是二者的对比:
1)XMPP协议基于繁重的XML,报文体积大,且交互繁琐;而MQTT协议报头只有两个字节,报文体积小,编解码容易。
2)XMPP基于JID的点对点的消息传输;MQTT协议基于主题(Topic)发布/订阅模式,消息路由更灵活。
3)XMPP协议采用XML承载报文,二进制必须进行Base64编码或其他方式处理,而XMPP并未定义报文格式,可采用Json,二进制等不同类型报文格式。
4)MQTT协议支持消息收发确认和QoS保证,有更好的消息保证性;而XMPP主协议并未定义类似机制
5)在嵌入式领域主要用C语言,C解析XML非常困难,而MQTT基于二进制实现,且未定义报文格式,更好地用于嵌入式开发。

综上,MQTT灵巧而简洁,对客户端开发者和服务端开发者都更友好。

5.4、MQTT与CoAP

CoAP也是与MQTT竞争的协议。其模仿HTTP的REST模型,服务端以URI方式创建资源,客户端可以通过GET、PUT、POST、DELETE等方式访问这些资源。

不过,如过使用CoAP协议可能会让物联网后台情况变得复杂,比如MQTT可以实现一个最简单的IoT架构:Device + MQTT服务器 + APP,手机端或Web端可以直接从MQTT服务器订阅想要的主题。而CoAP可能需要这样的架构:CoAP + Web + DB + App,使用CoAP必须经过DB才能转给第三发。

六、总结

MQTT协议的好处:

1、基于sub/pub的实现,解耦了消息发布者和订阅者
2、基于二进制的实现,节省了存储空间及流量
3、MQTT拥有更好的消息处理机制,可替代TCP Socket一部分应用场景

相比HTTP和XMPP,MQTT可以选择用户数据格式,解析复杂度低,同时MQTT也可用于手机推送等领域。

参考:https://blog.csdn.net/anxianfeng55555/article/details/80908795

MQTT有点:协议小、快、二进制、省带宽、QoS支持可靠传输

以上是关于MQTT协议学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

HI3861学习笔记(24)——MQTT客户端

ESP32学习笔记(46)——MQTT客户端

HI3861学习笔记(24)——MQTT客户端

MQTT 学习笔记以及在项目中的实际运用

中国移动物联网开放平台OneNET学习笔记——设备接入(MQTT协议)OneNET Studio篇

中国移动物联网开放平台OneNET学习笔记——设备接入(MQTT协议)OneNET Studio篇