环境

服务端 :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:只有一次,确保消息到达一次。这一级别可用于如下情况,在计费系统中,消息重复或丢失会导致不正确的结果。

wireshark显示黄色的报文 wireshark黑色报文_mqtt

上面描述的次数,只针对相邻的两个收发设备,客户端到服务器,服务器到客户端的消息数量,并不能保障客户端到客户端,因为客户端

到服务端之间有服务器。

如上面指的计费系统,就必须保证 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

只会向服务器发送一次报文

wireshark显示黄色的报文 wireshark黑色报文_服务器_02


qos = 1

只会向服务器发送一次报文,服务器响应客户端确认收到报文

wireshark显示黄色的报文 wireshark黑色报文_客户端_03


qos = 2

只向服务器发送一条报文,服务端响应客户端收到报文,服务端发送报文给订阅客户端,发送客户端释放消息并发送报文给服务器,

服务器发送确认消息到发送客户端,此时就保证服务器只有一条消息

wireshark显示黄色的报文 wireshark黑色报文_mqtt_04

理论上有这么多的组合,但是如果 publish 和 subscribe 两个客户端 qos 不同,则subscribe的qos以publish 的qos为准 mqtt 服务器,

如下几种组合报文是相同的

(pub(0),sub(0)) = (pub(0),sub(1))= (pub(0),sub(2))

wireshark显示黄色的报文 wireshark黑色报文_客户端_05


(pub(1),sub(1)) = (pub(1),sub(2))

wireshark显示黄色的报文 wireshark黑色报文_服务器_06


去掉几项重复的,可以得到不同报文有以下几项组合方式







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) 组合

wireshark显示黄色的报文 wireshark黑色报文_客户端_05


②、pub(1) sub(0) 组合

wireshark显示黄色的报文 wireshark黑色报文_服务器_08

③、pub(1) sub(1) 组合

wireshark显示黄色的报文 wireshark黑色报文_wireshark显示黄色的报文_09


④、pub(2) sub(0) 组合

wireshark显示黄色的报文 wireshark黑色报文_qos_10

⑤、pub(2) sub(1) 组合

wireshark显示黄色的报文 wireshark黑色报文_wireshark显示黄色的报文_11

⑥、pub(2) sub(2) 组合

wireshark显示黄色的报文 wireshark黑色报文_mqtt_12


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,客户端发送释放消息报文给服务端,服务端回复客户端发布完成确认。