MQTT协议探究(一)
1 准备阶段
- MQTT客户端:https://www.cnblogs.com/linzhanfly/p/9923577.html
- WireShark
- MQTT服务器(iot.eclipse.org)
- TCP:tcp://iot.eclipse.org:1883
- WebSocket:ws://iot.eclipse.org:80/ws
- MQTT协议(v3.1.1)下载地址:https://www.v2ex.com/t/209491
- 本文基于MQTT V3.1.1
2 MQTT控制报文格式
2.1 MQTT控制报文结构
- 固定报头,所有控制报文都包含
- 可变报头,部分控制报文包含
- 有效负载,部分控制报文包含
2.2 固定报头
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
byte 1 | MQTT 控制报文的类型 | 用于指定控制报文类型的标志符 | ||||||
byte 2 | 剩余长度(可变报头长度 + 有效负载长度) |
#### (1)MQTT控制报文的类型
- 仅显示部分,具体请参考协议,后面具体用到再说
名字 | 值 | 报文流动方向 | 描述 |
---|---|---|---|
CONNECT | 1 | client -> server | client 请求连接 server |
CONNACK | 2 | server -> client | 连接报文确认 |
PINGREQ | 12 | client -> server | 心跳请求 |
PINGRESP | 13 | server -> client | 心跳响应 |
DISCONNECT | 14 | client -> server | 客户端断开连接 |
(2)标识符
控制报文 | 固定报文标志 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
---|---|---|---|---|---|
CONNECT | Reserved | 0 | 0 | 0 | 0 |
CONNACK | Reserved | 0 | 0 | 0 | 0 |
PINGREQ | Reserved | 0 | 0 | 0 | 0 |
PINGRESP | Reserved | 0 | 0 | 0 | 0 |
DISCONNECT | Reserved | 0 | 0 | 0 | 0 |
(3)剩余长度
- 表示当前报文剩余部分的字节数,包括可变报头和负载的数据。
- 它采用了可变长度的编码方法。
- 允许最大长度256M
字节数 | 最小值 | 最大值 |
---|---|---|
1 | 0(0x00) | 127(0x7F) |
2 | 128(0x80,0x01) | 16383(0xFF,0x7F) |
3 | 16384(0x80,0x80,0x01) | 2097151(0xFF,0xFF,0x7F) |
4 | 2097152(0x80,0x80,0x80,0x01) | 268435455(0xFF,0xFF,0xFF,0x7F) |
2.3 可变报头
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
byte 1 | 报文标识符 MSB | |||||||
byte 2 | 报文标识符 LSB |
| 控制报文 | 报文标识符字段 |
| ---------- | -------------- |
| CONNECT | 不需要 |
| CONNACK | 不需要 |
| PINGREQ | 不需要 |
| PINGRESP | 不需要 |
| DISCONNECT | 不需要 |
2.4 有效载荷
控制报文 | 有效载荷 |
---|---|
CONNECT | 需要 |
CONNACK | 不需要 |
PINGREQ | 不需要 |
PINGRESP | 不需要 |
DISCONNECT | 不需要 |
3 MQTT控制报文示例
3.1 CONNECT——连接服务器
(1)WireShark抓包获取报文
MQ Telementry Transport Protocol, Connect Command
# 固定报头(2~5个字节)
Header Flags: 0x10 (Connect Command) # 固定报头,1个字节
0001 .... = Message Type: Connect Command(1) # 报文类型: CONNECT
.... 0000 = Reserved: 0 # 保留
Msg Len: 40 # 剩余长度,0x28,1个字节
# 可变报头,本例10个字节
Protocol Name Length: 4 # 协议长度,0x0004,2个字节
Protocol Name: MQTT # 协议名,MQTT(ASCII:0x4d515454),4个字节
Version: MQTT v3.1.1 (4) # 协议版本,0x04 1个字节
Connect Flags: 0xC2 # 连接标志,1个字节,每一位代表不同的内容
1... .... = User Name Flag: Set # 用户名
.1.. .... = Password Flag: Set # 密码
..0. .... = Will Retain: Not Set # 遗嘱保留
...0 0... = Qos Level: At most once deliver (Fire and Forget) (0) # Qos
.... .0.. = Will Flag: Not Set # 遗嘱
.... ..1. = Clean Session Flag: Set # 清除会话
.... ...0 = (Reserverd): Not Set # 固定为0
Keep Alive: 60 # 保持连接,2个字节,0x003C
# 有效载荷,本例30个字节
Client ID Length: 14,# 2个字节,0x000e
Client ID: MQTT_FX_client # 14个字节
User Name Length: 5 # 2个字节,0x0005
User Name: hello # 5个字节
Password Length: 5 # 2个字节,0x0005
Password: world # 5个字节
10 28 00 04 4d 51 54 54 04 c2 00 3c 00 0e 4d 51 .(..MQTT...<..MQ
54 54 5f 46 58 5f 43 6c 69 65 6e 74 00 05 68 65 TT_FX_Client..he
6c 6c 6f 00 05 77 6f 72 6c 64 llo..world
(2)连接标志
保留(第0位):固定为0
清理会话(第1位)设置为1,代表服务器不需要保存会话状态,即丢弃会话并开始一个新的会话;如果为0,需要根据保存的会话状态恢复当前会话。
- 客户端会话状态:
- 发送给Sever,但没有完成确认的Qos1和Qos2的消息
- 已经从接收,但没有完成确认的Qos2的消息
- 服务器会话状态:
- 会话是否存在
- 客户端的订阅消息
- 发送给Client,但没有完成确认的Qos1和Qos2消息
- 即将传输给Client的Qos1和Qos2消息
- 从Client接收,但没有完成确认的Qos2消息
- 可选,准备发送给Client的Qos0消息
- 客户端会话状态:
遗嘱标志(第2位):设置为1时,CONNECT报文的有效在载荷中包含Will Topic和Will Message字段,如果连接请求成功,遗嘱(Will Message)消息必须被存储在服务端。之后网络连接关闭时,服务端必须发布这个遗嘱消息,除非服务端收到DISCONNECT报文时删除了该遗嘱消息。下面情况将发生发布遗嘱消息:
- Server检测到一个I/O错误或者网络故障
- Client在Keep Alive时间内未能通信(既没有发送PING)
- Client没有先DISCONNECT报文就直接关闭了网络连接
- 协议错误Server关闭了网络连接
遗嘱Qos(第3 4位):用于指定发布遗嘱消息时的服务质量等级
- 遗嘱标志为0,遗嘱Qos也必须为0。
- 遗嘱标志为1,遗嘱Qos可以为任一服务质量等级。
遗嘱保留(第5位):遗嘱消息发布时是否需要保留。
用户名与密码标志(第6 7位)如果为1,代表有效载荷中带有用户名和密码,服务器可以获取并进行验证
(3)保持连接时间
2个字节表示,以秒为单位,最大值为18小时12分15秒
断开情况:
- Client发送PINGREQ,在合理时间内没有回来则关闭到Server的网络连接
- Server在1.5 * 保持连接时间 内没有收到Client的任意控制报文,它将断开Client的网络连接
设置为0,代表Server需要因为Client的不活跃而断开连接,但是Server仍然可以在需要的时候关闭连接。
(4)有效载荷
- 客户端标识符(Must):长度 + 标识符(大小写英文或数字),有效载荷的第一个字段,客户端可以提供一个零字节的ClientId,但是Clean Seesion必需为1.
- 遗嘱主体(Option):Will Topic
- 遗嘱消息(Option):Will Message
- 用户名(Option):Username
- 密码(Option)Password
(5)注意
MQTT Server允许Client发送完CONNECT就发送订阅或者发布消息,不过如果验证不通过,Server将关闭连接拒收后面的消息。
3.2 CONNACK——确认连接请求
(1)WireShark抓包获取报文
MQ Telementry Transport Protocol, Connect Command
# 固定报头(2~5个字节)
Header Flags: 0x20 (Connect Ack) # 固定报头,1个字节
0010 .... = Message Type: Connect Ack (2) # 报文类型: CONNACK
.... 0000 = Reserved: 0 # 保留
Msg Len: 2 # 剩余长度,0x02,1个字节
# 可变报头
Acknowledge Flags: 0x00 # 连接确认标志
0000 000. = Reserved: Not Set # 固定为0
.... ...0 = Session Present: Not Set # 当前会话标志
Return Code: Connection Accepted (0) # 连接返回码
(2)当前会话标志
- 如果Server收到一个CleanSession为1的连接,CONNACK报文中的返回码设置为0之外,还需要将CONNACK报文中的当前会话标志设置为0
- 如果Server收到一个CleanSeesion为0的连接,当前会话标志的值取决于Server是否保存了ClientId对应客户端的会话状态。如果保存了,当前会话标志设置为1,否则为0。
(3)连接返回码
值 | 返回码响应 | 描述 |
---|---|---|
0 | 0x00 | 连接已接收 |
1 | 0x01 | 不支持的协议版本 |
2 | 0x02 | 不合格的客户端标识符(UTF-8编码) |
3 | 0x03 | MQTT服务端不可用(TCP已连接) |
4 | 0x04 | 无效的用户名或密码 |
5 | 0x05 | 未授权此客户端 |
6-255 | 保留 |
3.3 PINGREQ——心跳请求
(1)WireShark抓包获取报文
Header Flags: 0xC0 (Ping Request) # 固定报头
1100 .... = Message Type: Ping Request (12)
.... 0000 = Reserved: 0
Msg Len: 0
(2)作用
- 在没有任何其他控制报文发送给Server时,Client告知Server还活着
- 请求Server发送响应确认Server是否活着
- 使用网络以确定网络连接没有断开
3.4 PINGRESP——心跳响应
(1)WireShark抓包获取报文
Header Flags: 0xD0 (Ping Response) # 固定报头
1101 .... = Message Type: Ping Response(13)
.... 0000 = Reserved: 0
Msg Len: 0
(2)作用
- 告知Client,Server活着
3.5 DISCONNECT——断开连接
(1)WireShark抓包获取报文
Header Flags: 0xe0 (Disconnect) # 固定报头
1110 .... = Message Type: Disconnect (14)
.... 0000 = Reserved: 0
Msg Len: 0
(2)作用
- 客户端正常断开连接
(3)响应
- Client发送DISCONNECT报文后
- 必需关闭网络连接
- 不能通过该连接继续发送任何控制报文
- Server收到DISCONNECT报文后
- 必须丢弃任何与当前连接关联的未发布的遗嘱消息
- 应该关闭网络连接,如果客户端还没有这么做
MQTT协议探究(一)的更多相关文章
- MQTT协议探究(三)
1 回顾与本次目标 1.1 回顾 主题通配符 主题语义和用法 WireShark进行抓包分析了报文 报文分析: SUBSCRIBE--订阅主题 SUBACK--订阅确认 UNNSUBSCRIBE--取 ...
- MQTT协议探究(二)
1 回顾与本次目标 1.1 回顾 MQTT控制报文的基本格式 WireShark进行抓包分析了报文 报文分析: CONNECT--连接服务器 CONNACK--确认连接请求 PINGREQ--心跳请求 ...
- WebSocket协议探究(三):MQTT子协议
一 复习和目标 1 复习 Nodejs实现WebSocket服务器 Netty实现WebSocket服务器(附带了源码分析) Js api实现WebSocket客户端 注:Nodejs使用的Socke ...
- WebSocket协议探究(序章)
一 WebSocket协议基于HTTP和TCP协议 与往常一样,进入WebSocket协议学习之前,先进行WebSocket协议抓包,来一个第一印象. WebSocket能实现客户端和服务器间双向.基 ...
- 海鑫智圣:物联网漫谈之MQTT协议
什么是MQTT协议 MQTT(消息队列遥测传输协议)是IBM在1999年专门针对物联网等应用场景来制订的轻量级双向消息传输协议,它主要是为了解决物联网上使用到的设备的互相通信的问题,以及这些设备与后端 ...
- 基于MQTT协议进行应用开发
官方协议有句如下的话来形容MQTT的设计思想: "It is designed for connections with remote locations where a "sma ...
- 云巴:基于MQTT协议的实时通信编程模型
概要 有人常问,云巴实时通信系统到底提供了一种怎样的服务,与其他提供推送或 IM 服务的厂商有何本质区别.其实,从技术角度分析,云巴与其它同类厂商都是面向开发者的通信服务,宏观的编程模型都是大同小异, ...
- MQTT协议(一)
MQTT(Message Queue Telemetry Transport),遥测传输协议,提供订阅/发布模式,更为简约.轻量,易于使用,针对受限环境(带宽低.网络延迟高.网络通信不稳定),可以简单 ...
- MQTT协议的简单介绍和服务器的安装
最近公司做的项目中有用到消息推送,经过多方面的筛选之后确定了使用MQTT协议,相对于XMPP,MQTT更加轻量级,并且占用用户很少的带宽. MQTT是IBM推出的一种针对移动终端设备的基于TCP/IP ...
随机推荐
- TCP/IP协议入门
TCP/IP协议入门 1. 简介 Transmission Control Protocol/Internet Protocol的简写,即传输控制协议/因特网互联协议.它是网络通信的一套协议集合. 先 ...
- IDEA 重复代码快速重构(抽取重复代码快捷键)
Ctrl+Alt+M 顺带一提,eclipse的快捷键是:Alt+Shift+M;
- Linux 配置eth0网卡
缘由: 最近要复习docker,电脑没有centos7,于是下载了一个最新版的centos7,迫于强迫症没有eth0网卡,为了将ens33改为eth0于是寻求方法. 1.编辑网卡的配置文件 vi /e ...
- springboot项目报Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is`...解
参考文章:https://blog.csdn.net/qq_42815754/article/details/83652253 <!-- MySql驱动 --> <dependenc ...
- (六)爬虫之使用selenium
selenium是使用javascript编写,主要用来进行web应用程序测试,在python爬虫中可以用来进行动态网页爬取,解决爬虫中的javascript渲染(执行js语句).总结记录下,以备后面 ...
- Airbnb新用户的民宿预定结果预测
1. 背景 关于这个数据集,在这个挑战中,您将获得一个用户列表以及他们的人口统计数据.web会话记录和一些汇总统计信息.您被要求预测新用户的第一个预订目的地将是哪个国家.这个数据集中的所有用户都来自美 ...
- 亿美软通 短信api
亿美软通 短信api 国际短信http标准协议文档和demo的地址: http://www.b2m.cn/static/doc/ims/ims_sendSingle.html import d ...
- 比特币nBits计算
转载:比特币源码分析(二十二) - 挖矿和共识 https://blog.csdn.net/yzpbright/article/details/81231351 CalculateNextWorkRe ...
- 利用Anaconda搭建TensorFlow环境并在Jupyter Notebook使用
打开Anaconda Prompt 创建一个tensorflow 虚拟环境:conda create -n tensorflow python=3.6 激活tensorflow虚拟环境activate ...
- 01.04 linux命令(2
======================Linux下的用户管理==============用户信息保存/etc/passwd ,一般用户都有读的权限真正的用户:修改密码,可以登录伪用户:应用程序在 ...