1. 1. MQTT协议
    1. 1.1. 配置环境
    2. 1.2. MQTT报文
      1. 1.2.1. 剩余长度
      2. 1.2.2. 服务质量等级
      3. 1.2.3. CONNECT
      4. 1.2.4. CONNACK
      5. 1.2.5. DISCONNECT
      6. 1.2.6. SUBSCRIBE
      7. 1.2.7. SUBACK
      8. 1.2.8. UNSUBSCRIBE
      9. 1.2.9. UNSUBACK
      10. 1.2.10. PING
      11. 1.2.11. PINGRSP
      12. 1.2.12. 报文分类
      13. 1.2.13. PUBLISH
        1. 1.2.13.1. Qos=0
        2. 1.2.13.2. Qos=1
        3. 1.2.13.3. Qos=2
      14. 1.2.14. 会话清理与保留
        1. 1.2.14.1. CONNECT的SP
      15. 1.2.15. 遗嘱
    3. 1.3. 资料

MQTT协议

MQTT是应用层协议,基于传输层的TCP发送

通常端口:1883

客户端给服务端发送,表示发布

服务端给客户端发送,表示推送

ClientID是用户名Username和密码Password相同下之下的多个角色,有记忆

配置环境

下载安装包
资料下载地址: https://pan.baidu.com/s/1qFuCzYW-lj1JnuUBcbiJxg 提取码: n25a
安装emqx作为服务端,打开PowerShell

输入bin/emqx start,接着在浏览器打开127.0.0.1:18083,网页默认用户名和密码是admin/public

使用网络调试助手和mqttx作为客户端

MQTT报文

剩余长度

剩余长度 = 可变报头长度 + 负载长度

可变长编码(1-4个字节)(128进制-----只要每个Byte的最高位为1,就继续往下读)

服务质量等级

  • 0:不需要签收,开销小
  • 1:需要1次签收
  • 2:需要一次签收,并且需要一次回访

CONNECT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//输入:
//固定报头(MQTT报文类型 + Reserved保留位) 剩余长度37 Byte

//可变报头00 04 + ‘M’+'Q'+'T'+'T' + 协议级别04
//+ 连接标志C2)+ 保持连接(10 64 --- 4196s,实际上是1.5倍)

//ClientID
//Username
//Password

10 25

00 04 4D 51 54 54 04 C2 10 64

00 07 55 53 45 52 30 30 31
00 07 55 53 45 52 30 30 31
00 07 55 53 45 52 30 30 31

//返回:
20 02 00 00

CONNACK

第1个字节是 连接确认标志,位7-1是保留位且必须设置为0

第0 (SP)位 是当前会话(Session Present)标志,即CONNECT的Clean Session。

DISCONNECT

DISCONNECT报文没有可变报头和有效载荷

1
E0 00

SUBSCRIBE

剩余长度等于可变报头的长度(2字节)加上有效载荷的长度

报文标识符,需要订阅和确认反馈一致,具体可以自己定义。

SUBACK

剩余长度等于可变报头的长度加上有效载荷的长度

0x80 - Failure(失败)

1
2
3
4
5
6
7
8
9
10
11
//发送:
//固定报头82 + 剩余长度0C
//报文标识符00 0A
//USER002长7字节,后续跟随USER002(Topic) + Qos(02)
82 0C
00 0A
00 07 55 53 45 52 30 30 32 02

//接收:
//固定报头90 + 剩余长度03 + 报文标识符00 0A +有效载荷 Qos(02)
90 03 00 0A 02

UNSUBSCRIBE

剩余长度等于可变报头的长度加上有效载荷的长度

UNSUBACK

剩余长度 = 0x02

1
2
3
4
5
6
7
8
9
10
11
// 发送:
// 固定报头A2 + 剩余长度
// 报文标识符12 34
// 长度表示00 07 + USER002(Topic)
A2 0B
12 34
00 07 55 53 45 52 30 30 32

// 接收:
// 固定报头 + 剩余长度 + 报文标识符
B0 02 12 34

PING

PING报文没有可变报头和有效载荷

1
C0 00

PINGRSP

PINGRSP报文没有可变报头和有效载荷

1
D0 00

报文分类

  • Qos=0的PUBLISH:发送方用到PUBLISH报文,没有接收方的事

  • Qos=1的PUBLISH:发送方用到PUBLISH报文,接收方PUBACK报文表示签收

  • Qos=2的PUBLISH:发送方先用到PUBLISH报文,接收方PUBREC报文表示签收;发送方再用PUBREL报文开启回访,接收方PUBCOMP报文表示回访确认

PUBLISH

在Qos=0时,DUP设置为0,即不重发

RETAIN = 1,Qos=0的带保留功能,即保留本条PUBLISH报文(最重要的,只有一条,后面关注的都会立即看到)。

有效负载就是需要发送的数据

有效载荷的长度计算:用固定报头中的剩余长度字段的值减去可变报头的长度。

Qos=0

1
2
3
4
5
6
//固定报头 + 剩余长度
//长度00 07 + 自己的topic(USER001)
//发送的字符串123
30 0C
00 07 55 53 45 52 30 30 31
31 32 33

Qos=1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//第一次发送,不带保留:
//固定报头 + 剩余长度
//长度 + USER001
//字符串123
32 0E
00 07 55 53 45 52 30 30 31 12 34
31 32 33

//接收方第一次没有签收,发送方后续重发,不带保留:
3A 0E
00 07 55 53 45 52 30 30 31 12 34
31 32 33

//User001显示
//40表示4号报文,接收成功;12 34是报文标识符
40 02 12 34

//User001签收(4号报文+长度+Qos=1)
40 02 00 01

没有签收,会一直发送请求,签收后就不会再发

Qos=2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//第一次发送,不带保留:
// 3号PUBLISH报文
34 0E
00 07 55 53 45 52 30 30 31 11 22
31 32 33

// 返回5号报文
(5)PUBREC: 50 02 00 01

//需要回访,否则再输入,USER002也不显示
(6)PUBREL: 62 02 11 22

//返回7号报文
(7)PUBCOMP : 70 02 00 01

//接收方第一次没有签收,发送方后续重发,不带保留:(如果是7号没有回访确认,不重发3号,而是重发6号报文)

3C 0E
00 07 55 53 45 52 30 30 31 11 22
31 32 33

(6)PUBREL: 62 02 11 22

(5)PUBREC: 50 02 00 01

(7)PUBCOMP : 70 02 00 01

会话清理与保留

  • 1:清理会话:没有记忆,不保留订阅。每次登陆后需要重新订阅需要的TOPIC收不到离线消息

  • 0:保留会话:有记忆,不用重新订阅TOPIC离线期间的消息(PUBLISH)我们可以收到

1
2
3
4
5
6
7
8
9
10
11
12
//1,清理
10 25
00 04 4D 51 54 54 04 C2 00 64
00 07 55 53 45 52 30 30 31
00 07 55 53 45 52 30 30 31
00 07 55 53 45 52 30 30 31
//0,保留
10 25
00 04 4D 51 54 54 04 C0 00 64
00 07 55 53 45 52 30 30 31
00 07 55 53 45 52 30 30 31
00 07 55 53 45 52 30 30 31

CONNECT的SP

Clean Session = 1 — SP= 0

Clean Session = 0,不一定

C2 C0 C0 C0 C0
0 0 1 1 1

遗嘱

很好,我选择跟它一起G了

报警功能,非正常断线(正常断线用14号报文,这里是直接断开TCP/被踢下线

服务器会向订阅了遗嘱TOPIC的客户端推送遗嘱PUBLISH报文

大白话:B订阅了A,A非正常断线,则B会收到A的遗嘱报文

USER002需要再订阅WILL001的遗嘱TOPIC

WILL001(遗嘱TOPIC)

WILL001(PUBLISH报文数据)

(可以不一样,设置一样是为了方便)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 固定报头 + 剩余长度
// 可变报头00 04 + ‘M’+'Q'+'T'+'T' + 协议级别04
// + 连接标志位C6)+ 保持连接(10 64 --- 4196s,实际上是1.5倍)
// Client_ID --- USER001
// WILL001 遗嘱TOPIC
// WILL001 PUBLISH报文数据
// Username --- USER001
// Password --- USER001
10 37
00 04 4D 51 54 54 04 C6 10 64

00 07 55 53 45 52 30 30 31
00 07 57 49 4C 4C 30 30 31
00 07 57 49 4C 4C 30 30 31
00 07 55 53 45 52 30 30 31
00 07 55 53 45 52 30 30 31

// 订阅USER002,然后再强制关闭USER001,可以看到遗嘱效果
82 0C
00 0A
00 07 57 49 4C 4C 30 30 32 02

资料

【2025新版】MQTT协议手把手详解 EMQX自建服务器 所有报文功能 逐个字节构建分析与测试_哔哩哔哩_bilibili

(11 封私信) MQTT协议,终于有人讲清楚了 - 知乎

MQTT协议详解(完整版)-CSDN博客