赞
踩
什么是MQTT?先从名字来看,Message Queuing Telemetry Transport:消息队列遥测传输。《MQTT 协议规范中文版》中的解释是:
MQTT 是一种基于客户端服务端架构的发布 / 订阅模式的消息传输协议。它的设计思想是轻巧、开放、 简单、规范,易于实现。这些特点使得它对很多场景来说都是很好的选择,特别是对于受限的环境如机器与 机器的通信( M2M )以及物联网环境( IoT )。
MQTT协议是应用层协议,其最大的优点是以极少的代码和有限的带宽(低开销、低带宽),为连接远程设备提供实时可靠的消息服务。
①使用发布/订阅消息模式,提供一对多的消息发布。
②基于TCP/IP提供网络连接(也有UDP版本)。
③根据消息的重要性不同设置不同的服务质量等级QoS。
④开销小,带宽占用小。
⑤使用 will 遗嘱机制来通知客户端异常断线。
⑥基于主题发布/订阅消息,对负载内容屏蔽的消息传输。
⑦支持心跳机制。
在MQTT中客户端既可以作为消息的发布者,也可以作为消息的订阅者。在下图中,手机和电脑客户端成为了 MQTT 信息的发布者而开发板则成为了 MQTT 信息的订阅者。
在MQTT中想要实现客户端的通信,必须借助服务端,所以必须先和服务器建立连接。其具体连接步骤分为以下两步:
①客户端向服务端发送一个请求连接的CONNECT报文,也就是发送了一个CONNECT数据包;
②MQTT服务端收到连接请求后,会向客户端发送连接确认的CONNACK报文,也就是 CONNACK 数据包。
CONNECT报文:
客户端发的的CINNECT报文必须符合规范,否则服务端会拒绝连接,CONNECT报文的主要内容如下:
可变头(Variable header):存在于部分类型的 MQTT 报文中,报文的类型决定了可变头是否存在及其具体的内容。
消息体(Payload):存在于部分类型的 MQTT 报文中,payload 就是消息载体的意思。
clientId--客户端 id
clientId 是 MQTT 客户端的标识,也就是 MQTT 客户端的名字,MQTT 服务端用该标识来识别客户端。因此 clientId 必须是独立的,如果两个MQTT客户端使用相同clientId 标识,服务端会把它们当成同一个客户端来处理。通常 clientId 是由一串字符所构成的。
keepAlive--心跳时间间隔
MQTT协议使用了类似心跳检测的方法来判断客户端是否在线。客户端可以定时向服务端发送一个心跳数据包来告知服务端,当前客户端在线,服务端在收到客户端的心跳数据包后,会回复一条消息,这条回复消息被称作心跳响应。keepAlive的单位为秒。
cleanSession--清除会话
这是一个布尔值,cleanSession 标志可用于控制客户端与服务端在连接和断开连接时的行为。连接服务端时 cleanSession=0,当 MQTT 客户端由离线(与服务端断开连接)再次上线时,离线期间发给客户端的所有 QoS>0 的消息仍然可以接收到; 如果连接服务端时cleanSession=1,当 MQTT 客户端由离线(与服务端断开连接)再次上线时,离线期间发给客户端的所有消息一律接收不到,并且服务器端也不会记住客户端在线期间订阅的主题。
也就是说:cleanSession 设置为 1,表示此次连接将创建一个新的临时会话,在客户端断开后,这个会话会自动销毁。而 cleanSession 设置为 0,表示创建一个持久性会话,在客户端断开连接时,会话仍然保持并保存离线消息,直到会话超时注销,并且会记住该客户端订阅的主题。
CONNACK 报文:
CONNACK报文主要内容如下:
returnCode--连接返回码
当服务端收到了客户端的连接请求后,会向客户端发送 returnCode(连接返回码),用来说明连接情况。 如果成功连接,则返回“0”。如果失败,则返回一个非零的数字:
返回码 | 说明 |
0 |
连接成功
|
1 |
连接被服务端拒绝,原因是不支持客户端的
MQTT
协议版本
|
2 |
连接被服务端拒绝,原因是不支持客户端标识符的编码。可能造成此原因的
是客户端标识符编码是
UTF-8
,但是服务端不允许使用此编码。
|
3 |
连接被服务端拒绝,原因是服务端不可用。即,网络连接已经建立,但
MQTT
服务不可用。
|
4 |
连接被服务端拒绝,原因是用户名或密码无效。
|
5 |
连接被服务端拒绝,原因是客户端未被授权连接到此服务端。
|
6-255 |
保留备用
|
如果客户端想要断开与服务端的连接,客户端可以主动向服务端发送一个DISCONNECT报文来断开与服务端的连接。
当客户端连接到服务端之后,就可以发布消息或订阅主题或取消订阅。
PUBLISH–发布消息
每条发布的消息必须指定一个“主题”,表示向该主题发布消息,发布消息就是向服务端发送一PUBLISH 报文,服务端收到客户端发送过来的 PUBLISH 报文之后,会向发送发回复一个报文。根据 QoS 的不同,回复的报文类型和过程会有所区别。
PUBLISH报文的主要内容为:
packetId--报文标识符
报文标识符可用于对 MQTT 报文进行标识,不同的 MQTT 报文所拥有的标识符不同。MQTT 设备可以通过该标识符对 MQTT 报文进行甄别和管理。报文标识符的内容与 QoS 级别有很大关系。
topicName--主题名字
这个就是发布消息时对应的主题的名字,一般是一个字符串。
payload--有效载荷
有效载荷就是我们希望通过 MQTT 所发送的实际内容,可以是字符串文本,也可以是图像。
qos--服务质量等级
QoS(Quality of Service)表示 MQTT 消息的服务质量等级。QoS 有三个级别:0、1 和 2,QoS 决定MQTT 通信有什么样的服务保证。
retain--保留标志
在默认情况下,当客户端订阅了某一主题后,并不会马上接收到该主题的信息。因为客户端订阅该主题之后,并没有其它客户端向该主题发布消息;但是在有些情况下,我们需要客户端在订阅了某一主题后马上接收到一条该主题的信息。这时候就需要用到保留标志这一信息。
dup--重发标志
dup 标志指示此消息是否是重复发送的消息。当 MQTT 报文的接收方没有及时向报文发送发回复确认收到报文时,发送方会以为对方没有收到信息,会再次重复发送 MQTT 报文在重复发送 MQTT 报文时,发送方会将此消息的dup设置为 true。请注意,重发标志只在 QoS 级别大于 0 时使用。
SUBSCRIBE--订阅主题
当客户端连接到服务端后,除了可以发布消息,也可以接收消息,但如果需要接收到消息,需要先订阅相关主题。
客户端是通过向服务端发送 SUBSCRIBE 报文来实现这一请求的。一个 SUBSCRIBE 报文可以用于订阅一个或者多个主题,并且客户端在订阅主题时也可以明确 QoS,服务端会根据 SUBSCRIBE 中的 QoS 来提供相应的服务保证。当客户端向服务端发送 SUBSCRIBE 报文,服务端接收到 SUBSCRIBE 报文之后会向客户端回复一个 SUBACK 报文(订阅确认报文)。SUBACK 报文包含有“订阅返回码”和“报文标识符”这两个信息。
returnCode--订阅返回码
返回码 | 说明 |
0x00
|
订阅成功
--QoS0
|
0x01
|
订阅成功
--QoS1
|
0x02
|
订阅成功
--QoS2
|
0x80
| 订阅失败 |
1)主题名
主题的基本形式就是一个字符串:区分大小写,可以使用空格(不建议使用),不能有中文。
2)主题分级
"home/sensor/led/brightness"
3)主题通配符
单级通配符:+
单级通配符可以匹配任意一个主题级别:
"home/sensor/+/status"
当客户端订阅了上述主题之后,将会收到以下主题的信息内容:
- "home/sensor/led/status"
- "home/sensor/key/status"
- "home/sensor/beeper/status"
- ......
多级通配符:#
多级通配符自然是可以匹配任意数量个主题级别:
"home/sensor/#"
当客户端订阅了上面这个主题之后,便可以收到如下注意的信息:
- "home/sensor/led"
- "home/sensor/key"
- "home/sensor/beeper"
- "home/sensor/led/status"
- "home/sensor/led/brightness"
- "home/sensor/key/status"
- "home/sensor/beeper/status"
- ......
QoS(Quality of Service)也就是服务质量,一个物联网通信中有些信息非常重要,我 们需要确保这类重要信息可以准确无误的发送和接收,而有些信息则相对不那么重要,这类信息如果在传输中丢失不会影响系统的运行;QoS就用来定义消息的重要性,并提供相对应的服务。
MQTT 设计了一套保证消息稳定传输的机制,包括消息应答、存储和重传。在这套机制下,提供了三种不同级别的 QoS(Quality of Service),也就是 MQTT 协议有三种服务质量等级:
QoS = 0:最多发一次:
0 是服务质量 QoS 的最低级别。当 QoS 为 0 级时,MQTT 协议并不保证所有信息都能得以传输。也就是说,QoS=0 的情况下,MQTT 服务端和客户端不会对消息传输是否成功进行确认和检查。消息能否成功传输全看网络环境是否稳定。也就是说发送一次之后就不管了,最多一次,不管发送是否失败!发送端一旦发送完消息后,就完成任务了,发送端不会检查发出的消息能否被正确接收到。在网络环境稳定的情况下,信息传输一般是不会出现问题的。这完全依赖于 TCP 重传机制,如果网络 不好,TCP 的重传也不是 100%可靠,加上 MQTT 是发送方发出去的消息是依赖代理服务器完成转发的,所以消息最多一次。
QoS = 1:最少发一次:
当 QoS 级别为 1 时,发送端在消息发送完成后,会检查接收端是否已经成功接收到了消息。发送端向接收端发送 PUBLISH 报文,当接收端收到 PUBLISH 报文后会向发送端回复PUBACK报 文,如果发送端收到 PUBACK 报文,那么它就知道消息已经被接收端成功接收! 假如过了一段时间后,发送端没有收到 PUBACK 报文,那么发送端会再次发送消息(发送PUBLISH 报文),然后再次等待接收端的 PUBACK 确认报文。因此,当 QoS=1 时,发送端在一定时间内没有收到接 收端的 PUBACK 确认报文,会重复发送同一条消息。 所以 QoS=1 时,每一条消息就至少会传输一次,但也可能会重复传输多次。当发送端重复发送一条消 息时,会将 PUBLISH 报文中的 dup 标志设置为 true。这就是为了告诉接收端,此消息 为重复发送的消息,那么我们的 MQTT 客户端在接收到消息之后,可以去判断 dup 标志以确定此消息是否 为重复消息,应用程序应该对此作出相应的处理。
QoS = 2:保证收一次:
MQTT 服务质量最高级是 2 级,即 QoS=2。当 MQTT 服务质量为 2 级时,MQTT 协议可以确保接收端只接收一次消息(注意是只接收到一次,在 QoS=1 的情况下,接收端接收到消息的次数可能不止一次:>=1)
①、首先发送端向接收端发送 PUBLISH 报文;
前面我们提到,PUBLISH 报文中有一个 retain 标志,也就是保留标志,是一个布尔值,当 retain 设置为true 时表示保留消息,如果设置为 false 表示不保留消息。
保留消息的作用
保留消息的作用就是让服务端对客户端发布的消息进行保留,如果有其它客户端订阅了该消息对应的主题时,服务端会立即将保留消息推送给订阅者,而不必等到发送者向主题发布新消息时订阅者才会收到消息。
更新保留消息
每一个主题只能有一个“保留消息”,如果客户端想要更新“保留消息”,就需要 向该主题发送一条新的“保留消息”,这样服务端会将新的“保留消息”覆盖旧的“保留消息”。当有客户 端订阅该主题时,服务端就会将最新的“保留消息”发送给订阅者。
删除保留消息
只需要向该主题发布一条空的“保留消息”, 即可。
心跳机制的原理:让客户端在没有向服务端发送消息的这个空闲时间里,定时向服务端发送一个 心跳包,这个心跳包被称为心跳请求,其实质就是向服务端发送一个 PINGREQ 报文;当服务端收到PINGREQ报文后就知道该客户端依然在线,然后向客户端回复一个 PINGRESP 报文,称为心跳响应。通过 keepAlive 设置时间间隔,当服务器未收到客户端的心跳包,那么服务器就会知道, 这台客户端可能已经掉线了。如果客户端在发送心跳请求(PINGREQ)后,没有收到服务端的心跳响应(PINGRESP),那么客户端就会认为自己与服务端已经断开连接了。
客户端断开与服务端的连接通常是有两种方式的:
这几个参数都是以 will(遗嘱)开头的,需要在客户端连接服务端时就需要设置好:
willTopic -- 遗嘱主题
遗嘱消息和普通 MQTT 消息很相似,也有主题和正文内容。willTopic 的作用正是告知服务端,本客户端的遗嘱主题是什么。只有那些订阅了这一遗嘱主题的客户端才会收到本客户端的遗嘱消息。客户端也可以主动向遗嘱主题发布消息,这样通常会有一些妙用,譬如当客户端 A 上线时可以向自己的遗嘱主题发布一条消息,那么那些订阅了该遗嘱主题的客户端可以收到这条消息,这些订阅者也就知道了客户端 A 已经上线了。
willMessage -- 遗嘱消息
遗嘱消息定义了遗嘱的内容。在本示例中,那些订阅了主题“clientWill”的客户端会在客户端意外断线时,收到服务端发布的“client offline”这样的信息。
willRetain -- 遗嘱消息的保留标志
遗嘱消息也可以设置为保留标志,用于告诉服务端是否需要对遗嘱消息进行保留处理。
willQoS -- 遗嘱消息的 QoS
CONNECT报文中还有两个参数:username(用户名)和 password(密码),这里的用户名和密码是客户端连接服务端时进行认证所需要的。有些 MQTT 服务端需要客户端在连接时提供用户名和密码,只有客户端正确提供了用户名和密码后, 才能连接服务端,否则服务端将会拒绝客户端连接。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。