环境
服务端 :EMQ
客户端:
let mqtt = require('mqtt')
let options = {
'username': 'clientB',
'password': '123456',
'clientId': '1597279339',
'keepalive': 90,
'connectTimeout': 3000,
'clean': true
}
let client = mqtt.connect('tcp://39.99.222.146:1883',options)
client.on('connect', function () {
client.publish('apple', "nice to meet you",{'qos':2}, function (err) {
})
})
抓包工具:Wireshark
qos简介
qos 即消息质量在大多数数据以及资料中你都会看到这样的描述
qos = 0:至多一次,消息发布完全依赖底层 TCP/IP 网络。会发生消息丢失或重复。这一级别可用于如下情况,环境传感器数据,丢失
一次读记录无所谓,因为不久后还会有第二次发送。
qos = 1:至少一次,确保消息到达,但消息重复可能会发生。
qos = 2:只有一次,确保消息到达一次。这一级别可用于如下情况,在计费系统中,消息重复或丢失会导致不正确的结果。
上面描述的次数,只针对相邻的两个收发设备,客户端到服务器,服务器到客户端的消息数量,并不能保障客户端到客户端,因为客户端
到服务端之间有服务器。
如上面指的计费系统,就必须保证 publish 端和 subscribe 端 qos 都为2,只有这样才能保证发布一条消息并且只接收一条消息。
列出 publish 和 subscribe qos 的所有组合如下
publish qos | pub(0) | pub(0) | pub(0) | pub(1) | pub(1) | pub(1) | pub(2) | pub(2) | pub(2) |
subscribe qos | sub(0) | sub(1) | sub(2) | sub(0) | sub(1) | sub(2) | sub(0) | sub(1) | sub(2) |
抓包分析
下面是发送的报文,Wireshark 抓包可以使用 ip.addr == 39.99.222.146 or ip.addr == 192.168.20.72 and mqtt,
替换为你的服务器地址和客户端地址,因为我是在一台电脑模拟两个客户端,所以设备IP相同,有条件的可以试试用两个IP,抓包时更加
直观
qos = 0
只会向服务器发送一次报文
qos = 1
只会向服务器发送一次报文,服务器响应客户端确认收到报文
qos = 2
只向服务器发送一条报文,服务端响应客户端收到报文,服务端发送报文给订阅客户端,发送客户端释放消息并发送报文给服务器,
服务器发送确认消息到发送客户端,此时就保证服务器只有一条消息
理论上有这么多的组合,但是如果 publish 和 subscribe 两个客户端 qos 不同,则subscribe的qos以publish 的qos为准 mqtt 服务器,
如下几种组合报文是相同的
(pub(0),sub(0)) = (pub(0),sub(1))= (pub(0),sub(2))
(pub(1),sub(1)) = (pub(1),sub(2))
去掉几项重复的,可以得到不同报文有以下几项组合方式
① | ② | ③ | ④ | ⑤ | ⑥ | |
publish qos | pub(0) | pub(1) | pub(1) | pub(2) | pub(2) | pub(2) |
subscribe qos | sub(0) | sub(0) | sub(1) | sub(0) | sub(1) | sub(2) |
下面截图标注的 publish 以及 subcribe 指明报文是服务器和发布端还是订阅端交互
①、pub(0) sub(0) 组合
②、pub(1) sub(0) 组合
③、pub(1) sub(1) 组合
④、pub(2) sub(0) 组合
⑤、pub(2) sub(1) 组合
⑥、pub(2) sub(2) 组合
PUBLISH 报文固定报头
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
byte1 | MQTT 控制报文类型 (3) | DUP | QoS 等级 | RETAIN | ||||
0 | 0 | 1 | 1 | x | x | x | x | |
byte2 | 剩余长度 |
DUP 标志被设置为 0,表示这是客户端或服务端第一次请求发送这个 PUBLISH 报文。如果 DUP 标志被设置为 1,表示这可能是一个
早前报文请求的重发。
由上面抓包结合 publish 固定报头可以发现
对于 qos = 0
该消息最多只发送一次,或者在通过网络的传送受阻的时候根本不发送。
qos = 1
该消息至少发送一次。如果发送方没有收到PUBACK确认包,则会再次发送加上 DUP 标志的该消息,直到收到确认包为止。(上面抓包
过程中,连接很稳定没遇到重复发的问题)
qos =2
QoS = 2 是最安全但也是最慢的传输模式。要进行两次交互客户端向服务端发送 publish message 报文,服务端响应客户端收到报文
publish received,客户端发送释放消息报文给服务端,服务端回复客户端发布完成确认。