教你动手写网络协议栈-MQTT报文解析6-解析

教你动手写网络协议栈系列文章

序号 内容
1 《教你动手写UDP协议栈-UDP协议栈格式》
2 《教你动手写UDP协议栈-DHCP报文解析》
3 《教你动手写UDP协议栈-OTA上位机》
4 《教你动手写UDP协议栈-DNS报文解析》
5 《教你动手写UDP协议栈-CoAP报文解析 》
6 《教你动手写网络协议栈-MQTT报文解析-实践 》
7 《教你动手写网络协议栈-MQTT报文解析-解析 》

概述

  • 在上一篇文章,直接在本地搭建了服务器和客户端,简单的实践了MQTT的用法。而这一篇来解析MQTT的报文格式。MQTT的报文字段很精简。但是解析起来还是有些复杂的。
  • 解析报文最好的工具是采用wireshark抓包,不过我发现,wireshark的2.xxx的版本无法进行回环抓包(即无法抓取127.0.0.1的数据报文)。通过一番度娘,发现新版本的wireshark用Npcap替换WinPcap,Npcap是基于WinPcap 4.1.3开发的,api兼容WinPcap。下载链接:https://www.wireshark.org/download.html
  • MQTT的标准可以参考如下网站:
    http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718030

MQTT报文

MQTT报文格式

  • MQTT的报文字段主要包含3部分,如下表:
名称 说明
Fixed header(固定报文头) 所有MQTT报文都包含
Variable header(可变报文头) 只有部分MQTT报文包含
Payload(MQTT数据段) 只有部分MQTT报文包含

MQTT固定报文头[Fixed header]

  • 每个MQTT报文都包含一个固定报文头,固定报文头部格式如下:
  bit    7     6     5     4     3     2     1     0
+-----+-----+-----+-----+-----+-----+-----+-----+-----+
|Byte1|   MQTT控制报文类型    |指定控制报文类型的标志 |
+-----+-----------------------------------------------|
|Byte2|                   剩余长度                    |
+-----+-----------------------------------------------|
| ... |                   剩余长度                    |
+-----------------------------------------------------|
MQTT控制报文类型
  • MQTT的控制报文类型在固定报文头的第1个字节的4 ~ 7bit,共4位无符号值。这些值如下表描述:
类型 报文方向 描述
RESERVED 0 禁止 保留
CONNECT 1 客户端到服务端 客户端请求连接服务器
CONNACK 2 服务端到客户端 连接报文确认
PUBLISH 3 双向 发布消息
PUBACK 4 双向 QoS 1消息发布收到确认
PUBREC 5 双向 发布收到(保证交付第一步)
PUBREL 6 双向 发布释放(保证交付第二)
PUBCOMP 7 双向 QoS 2消息发布完成
SUBSCRIBE 8 客户端到服务端 客户端订阅请求
SUBACK 9 服务端到客户端 订阅请求报文确认
UNSUBSCRIBE 10 客户端到服务端 客户端取消订阅请求
UNSUBACK 11 服务端到客户端 取消订阅请求报文确认
PINGREQ 12 客户端到服务端 心跳请求
PINGRESP 13 服务端到客户端 心跳响应
DISCONNECT 14 客户端到服务端 客户端断开连接
RESERVED 15 禁止 保留
MQTT控制报文标志
  • MQTT的控制报文标志在固定报文头的第1个字节的4 ~ 7bit,包含每个MQTT报文类型的特定的标志。
  • 注意:如果接收方收到非法的标志,接受者必须关闭网络连接。标志如下表:
  • 其中:
    • DUP:控制报文的重复分发标志
    • QoS:PUBLISH报文的服务质量等级
    • RETAIN:PUBLISH报文的保留标志
类型 报文标志 Bit3 Bit2 Bit1 Bit0
CONNECT Reserved 0 0 0 0
CONNACK Reserved 0 0 0 0
PUBLISH Used in MQTT 3.1.1 DUP QoS QoS RETAIN
PUBACK Reserved 0 0 0 0
PUBREC Reserved 0 0 0 0
PUBREL Reserved 0 0 1 0
PUBCOMP Reserved 0 0 0 0
SUBSCRIBE Reserved 0 0 1 0
SUBACK Reserved 0 0 0 0
UNSUBSCRIBE Reserved 0 0 1 0
UNSUBACK Reserved 0 0 0 0
PINGREQ Reserved 0 0 0 0
PINGRESP Reserved 0 0 0 0
DISCONNECT Reserved 0 0 0 0
MQTT报文剩余长度
  • 剩余长度字段从固定报文头的第2个字节开始,最长可达4个字节,所以剩余长度访问是Byte[2 ~ 5]。
  • 剩余长度表示当前报文剩余部分的字节数,包含可变头部和Payload。
  • 上面的描述,那么怎么确定其长度用几个字节来描述呢?答案:取决于字节的最高位Bit7(默认都是在搞自己在前);如果Bit7为1,那么需要继续计算字节长度,如果Bit7为0,那么不需要继续计算字节长度。
  • 消息长度可以简单理解为128禁止的数据,4位长度最大可以表示:128 * 128 * 128 * 128 Byte = 256MB。
  • 需注意计算规则,低位在前,高位在后,字节最高位Bit7标记是否继续计算消息长度。其消息长度范围如下表:
字节 最小值 最大值
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)
  • 举例:
    • 第一字节最高位是1,需要继续向后计算,去掉标记位(0xC1%128),得到1000001=41
    • 第二字节最高位是1,需要继续向后计算,去掉标记位(0xC2%128),得到1000010=42
    • 第三字节最高位是0,不需要向后计算,其结果就是0x33=51
    • 因为低位在前,高位在后,即消息长度为:41 + 42 * 128 + 51 * 128 * 128=841001Byte = 821KB
    • 0xC1 = 11000001
    • 0xC2 = 11000010
    • 0x33 = 00110011
  1. 消息长度是0x60,其二进制是01100000b,字节最高位Bit7位0,所以不需要往后计算,其十进制是96(即消息长度为96个字节)。
  2. 消息长度是0xC1, 0xC2, 0x33。分别二进制为:

MQTT可变报文头[Variable header]

  • 在某些MQTT控制报文包含了一个可变报文头部分,它在固定报文头和payload之间,可变报头的内容根据报文类型的不同而不同,可变报头的报文标识符(Packet Identifier)字段存在与多个类型的报文里。可变报头其实就是MQTT开发中使用的Packet ID,通过Packet ID 进行一些操作确认。包含Packet ID的报文类型如下:
类型 包含可变报文头
PUBLISH √(QoS > 0)
PUBACK
PUBREC
PUBREL
PUBCOMP
SUBSCRIBE
SUBACK
UNSUBSCRIBE
UNSUBACK
  • Packet ID默认是从1开始并自增,如果一个Packet ID被用完后,这个Packet ID可以被重用。对于PUBLISH(QoS 1)来说,如果发送端接收到PUBACK,那么这个Packet ID就用完了。对于PUBLISH(QoS 2),如果接收方收到PUBCOMP,那么这个Packet ID就用完了。对于SUBSCRIBE和UNSUBSCRIBE,Packet ID使用完成的标记是发送方收到了对应的SUBACK和UNSUBACK。

MQTT数据段[Payload]

  • MQTT中有些报文类型是包含Payload
  • 如PUBLISH的Payload指消息内容。
  • 如CONNECT的Payload指Client Identifier,Will Topic,Will Message,Username,Password等信息
  • 包含Payload的报文类型如下:
类型 包含Payload
CONNECT
PUBLISH 可选
SUBSCRIBE
SUBACK
UNSUBSCRIBE

通过wireshark分析MQTT报文

  • 因为我们的服务器和客户端是在PC上搭建的,所以需要通过wireshark的回环抓包,来分析报文类型CONNECT和CONNACK。
  1. 打开wireshark,选择进行回环抓包
  1. 使用MQTT.fx创建一个客户端,点击连接,便可以抓到CONNECT和CONNACK的报文。
  1. 红色圈子的报文类型CONNECT的内容:
内容:
10 25
00 04 451 54 54
04
c2
00 3c
00 08 63 669 65 674 30 31
00 05 61 64 669 6e
00 08 31 32 33 34 35 36 37 38
  1. 报文类型CONNECT内容分析:
  • 0x10:高四位0001,代表报文类型:CONNECT。
  • 0x25:二进制-0010 0101,Bit7为0,所以剩余长度只有一个字节长,即0x25十进制:37个字节
  • 0x00 0x04 0x4d 0x51 0x54 0x54:其中-0x00,0x04表示协议长度;0x4d 0x51 0x54 0x54对应 "M", "Q", "T", "T"。
  • 0x04:代表MQTT版本号:v3.1.1
  • 0xc2: 次字节含义如下表,该字节描述紧跟数据有 User Name、Password,没有遗嘱设置,选择了清理会话方式与服务器连接。
Bit 7 6 5 4 3 2 1 0
含义 User Name Flag Password Flag Will Retain Flag Will QoS MSB Will QoS LSB Will Flag Clean session Rreserved
1 1 0 0 0 0 1 0
  • 00 3c:对应十进制为60,即保持连接(Keep Alive)60秒,以秒为单位,它是指在客户端传输完成一个控制报文的时刻到发送下一个报文的时刻,两者之间允许空闲的最大时间间隔。客户端负责保证控制报文发送的时间间隔不超过保持连接的值。如果没有任何其它的控制报文可以发送,客户端 必须发送一个PINGREQ 报文。客户端随时可以发送ping指令,服务器如果发现在KeepAalive时间内没有收到客户端的消息,会自动断开与客户端建立的连接。
  • 00 08 63 6c 69 65 6e 74 30 31:其中-0x00, 0x08表示clientID的长度8个字节;0x63,0x6c,0x69,0x65,0x6e,0x74,0x30,0x31:代表client01。即是我们在MQTT.fx创建客户端的时候设置clientID。
  • 00 05 61 64 6d 69 6e:其中-0x00,0x05表示User Name的的长度5个字节;0x61,0x64,0x6d,0x69,0x6e:代表User Name为admin, 即是我们在MQTT.fx创建客户端的时候设置User Name。
  • 00 08 31 32 33 34 35 36 37 38:其中-0x00,0x08表示User Name的的长度8个字节;0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38:代表Password为12345678, 即是我们在MQTT.fx创建客户端的时候设置Password。
  1. 红色圈子的报文类型CONNACK的内容:
内容:
20
02
00
00
  1. 报文类型CONACK内容分析:
  • 20:高四位0010,代表报文类型:CONNACK。
  • 02:二进制-0000 0010,Bit为0,所以剩余长度只有一个字节长,即0x02十进制:2个字节。
  • 00:可变头部的第一个字节的第0位连接确认。
  • 00:可变头部的第二个字节。
返回码响应 描述
0 0x00连接已接受 连接已被服务器接受
1 0x01连接已拒绝,不支持的协议版本 服务器不支持客户端请求的协议版本
2 0x02连接已拒绝,不合格的客户端ID 客户端ID是正确的UTF-8码,但服务器不允许使用
3 0x03连接已拒绝,服务端不可用 网络连接已建立,但MQTT服务不可用
4 0x04连接已拒绝,无效的用户名或密码 用户名或密码的数据格式无效
5 0x05连接已拒绝,未授权 客户端未被授权连接到此服务器
6-255 Reserved 保留




RT-Thread线下技术培训:MQTT网关


本次培训RT-Thread将以ART-Pi为硬件平台+RT-Thread物联网操作系统提供MQTT网关原型,希望帮助工程师快速熟悉基于RT-Thread的项目开发流程,熟悉MQTT网关开发中所涉及到的技术要点如Modbus、MQTT、连网、文件系统、FTP、Bootloader、OTA、裁剪优化,提升产品开发速度。


我们将到访的城市有:上海、深圳、南京、广州、郑州、北京、武汉、天津、成都、西安


长按识别上方二维码报名




可以添加微信17775982065为好友,注明:公司+姓名,拉进 RT-Thread 官方微信交流群!



点击阅读原文报名培训
RTThread物联网操作系统 帮助您了解RT-Thread相关的资讯.
评论
  • RDDI-DAP错误通常与调试接口相关,特别是在使用CMSIS-DAP协议进行嵌入式系统开发时。以下是一些可能的原因和解决方法: 1. 硬件连接问题:     检查调试器(如ST-Link)与目标板之间的连接是否牢固。     确保所有必要的引脚都已正确连接,没有松动或短路。 2. 电源问题:     确保目标板和调试器都有足够的电源供应。     检查电源电压是否符合目标板的规格要求。 3. 固件问题: &n
    丙丁先生 2024-12-01 17:37 114浏览
  • 作为优秀工程师的你,已身经百战、阅板无数!请先醒醒,新的项目来了,这是一个既要、又要、还要的产品需求,ARM核心板中一个处理器怎么能实现这么丰富的外围接口?踌躇之际,你偶阅此文。于是,“潘多拉”的魔盒打开了!没错,USB资源就是你打开新世界得钥匙,它能做哪些扩展呢?1.1  USB扩网口通用ARM处理器大多带两路网口,如果项目中有多路网路接口的需求,一般会选择在主板外部加交换机/路由器。当然,出于成本考虑,也可以将Switch芯片集成到ARM核心板或底板上,如KSZ9897、
    万象奥科 2024-12-03 10:24 96浏览
  •         温度传感器的精度受哪些因素影响,要先看所用的温度传感器输出哪种信号,不同信号输出的温度传感器影响精度的因素也不同。        现在常用的温度传感器输出信号有以下几种:电阻信号、电流信号、电压信号、数字信号等。以输出电阻信号的温度传感器为例,还细分为正温度系数温度传感器和负温度系数温度传感器,常用的铂电阻PT100/1000温度传感器就是正温度系数,就是说随着温度的升高,输出的电阻值会增大。对于输出
    锦正茂科技 2024-12-03 11:50 143浏览
  • 当前,智能汽车产业迎来重大变局,随着人工智能、5G、大数据等新一代信息技术的迅猛发展,智能网联汽车正呈现强劲发展势头。11月26日,在2024紫光展锐全球合作伙伴大会汽车电子生态论坛上,紫光展锐与上汽海外出行联合发布搭载紫光展锐A7870的上汽海外MG量产车型,并发布A7710系列UWB数字钥匙解决方案平台,可应用于数字钥匙、活体检测、脚踢雷达、自动泊车等多种智能汽车场景。 联合发布量产车型,推动汽车智能化出海紫光展锐与上汽海外出行达成战略合作,联合发布搭载紫光展锐A7870的量产车型
    紫光展锐 2024-12-03 11:38 126浏览
  • 概述 说明(三)探讨的是比较器一般带有滞回(Hysteresis)功能,为了解决输入信号转换速率不够的问题。前文还提到,即便使能滞回(Hysteresis)功能,还是无法解决SiPM读出测试系统需要解决的问题。本文在说明(三)的基础上,继续探讨为SiPM读出测试系统寻求合适的模拟脉冲检出方案。前四代SiPM使用的高速比较器指标缺陷 由于前端模拟信号属于典型的指数脉冲,所以下降沿转换速率(Slew Rate)过慢,导致比较器检出出现不必要的问题。尽管比较器可以使能滞回(Hysteresis)模块功
    coyoo 2024-12-03 12:20 170浏览
  • 光伏逆变器是一种高效的能量转换设备,它能够将光伏太阳能板(PV)产生的不稳定的直流电压转换成与市电频率同步的交流电。这种转换后的电能不仅可以回馈至商用输电网络,还能供独立电网系统使用。光伏逆变器在商业光伏储能电站和家庭独立储能系统等应用领域中得到了广泛的应用。光耦合器,以其高速信号传输、出色的共模抑制比以及单向信号传输和光电隔离的特性,在光伏逆变器中扮演着至关重要的角色。它确保了系统的安全隔离、干扰的有效隔离以及通信信号的精准传输。光耦合器的使用不仅提高了系统的稳定性和安全性,而且由于其低功耗的
    晶台光耦 2024-12-02 10:40 144浏览
  • 11-29学习笔记11-29学习笔记习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-02 23:58 92浏览
  • TOF多区传感器: ND06   ND06是一款微型多区高集成度ToF测距传感器,其支持24个区域(6 x 4)同步测距,测距范围远达5m,具有测距范围广、精度高、测距稳定等特点。适用于投影仪的无感自动对焦和梯形校正、AIoT、手势识别、智能面板和智能灯具等多种场景。                 如果用ND06进行手势识别,只需要经过三个步骤: 第一步&
    esad0 2024-12-04 11:20 109浏览
  • 遇到部分串口工具不支持1500000波特率,这时候就需要进行修改,本文以触觉智能RK3562开发板修改系统波特率为115200为例,介绍瑞芯微方案主板Linux修改系统串口波特率教程。温馨提示:瑞芯微方案主板/开发板串口波特率只支持115200或1500000。修改Loader打印波特率查看对应芯片的MINIALL.ini确定要修改的bin文件#查看对应芯片的MINIALL.ini cat rkbin/RKBOOT/RK3562MINIALL.ini修改uart baudrate参数修改以下目
    Industio_触觉智能 2024-12-03 11:28 112浏览
  • 最近几年,新能源汽车愈发受到消费者的青睐,其销量也是一路走高。据中汽协公布的数据显示,2024年10月,新能源汽车产销分别完成146.3万辆和143万辆,同比分别增长48%和49.6%。而结合各家新能源车企所公布的销量数据来看,比亚迪再度夺得了销冠宝座,其10月新能源汽车销量达到了502657辆,同比增长66.53%。众所周知,比亚迪是新能源汽车领域的重要参与者,其一举一动向来为外界所关注。日前,比亚迪汽车旗下品牌方程豹汽车推出了新车方程豹豹8,该款车型一上市就迅速吸引了消费者的目光,成为SUV
    刘旷 2024-12-02 09:32 140浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦