MQTT协议详解 二、MQTT控制包格式

   日期:2020-11-03     浏览:148    评论:0    
核心提示:MQTT控制包格式MQTT控制包格式MQTT控制包由一下三个部分组成顺序名称描述1固定包头所有MQTT包中2可变包头某些MQTT包中3载荷某些MQTT包中固定包头 Bit 7 6 5 4 3 2 1 0 byte1 控制包类型 控制包类型标识 byte2

文章目录

  • 系列文章目录
  • 前言
  • 一、MQTT控制包格式
  • 二、固定包头
    • 控制包类型
    • 控制包类型标识
    • 剩余长度
  • 三、可变包头
    • 数据包标识
  • 四、载荷

系列文章目录

MQTT协议详解 一、MQTT简介

MQTT协议详解 二、MQTT控制包格式

前言

本章接详细介绍MQTT的控制包数据组成。

一、MQTT控制包格式

MQTT控制包由一下三个部分组成

顺序 名称 描述
1 固定包头 所有MQTT包中
2 可变包头 某些MQTT包中
3 载荷 某些MQTT包中

二、固定包头

Bit 7 6 5 4 3 2 1 0
byte1 控制包类型 控制包类型标识
byte2 剩余长度

控制包类型

位置:第一个字节

名称 传输方向 描述
Reserved 0 保留
CONNECT 1 客户端 --> 服务端 客户端连接请求
CONNACK 2 服务端 --> 客户端 服务器响应客户端连接请求
PUBLISH 3 客户端 --> 服务端 OR 服务端 --> 客户端 发布消息
PUBACK 4 客户端 --> 服务端 OR 服务端 --> 客户端 发布消息响应
PUBREC 5 客户端 --> 服务端 OR 服务端 --> 客户端 发布消息到达 (交付第一步 )
PUBREL 6 客户端 --> 服务端 OR 服务端 --> 客户端 发布消息释放 (交付第二步)
PUBCOMP 7 客户端 --> 服务端 OR 服务端 --> 客户端 发布消息完成 (交付第三步)
SUBSCRIBE 8 客户端 --> 服务端 客户端订阅请求
SUBACK 9 服务端 --> 客户端 服务器响应客户端订阅请求
UNSUBSCRIBE 10 客户端 --> 服务端 取消订阅请求
UNSUBACK 11 服务端 --> 客户端 响应取消订阅请求
PINGREQ 12 客户端 --> 服务端 心跳请求
PINGRESP 13 服务端 --> 客户端 心跳响应
DISCONNECT 14 客户端 --> 服务端 客户端断开连接
Reserved 15 保留

控制包类型标识

控制包类型 固定标志 bit3 bit2 bit1 bit0
CONNECT 保留 0 0 0 0
CONNACK 保留 0 0 0 0
PUBLISH 根据实际传输情况设置 DUP QoS QoS RETAIN
PUBACK 保留 0 0 0 0
PUBREC 保留 0 0 0 0
PUBREL 保留 0 0 1 0
PUBCOMP 保留 0 0 0 0
SUBSCRIBE 保留 0 0 1 0
SUBACK 保留 0 0 0 0
UNSUBSCRIBE 保留 0 0 1 0
UNSUBACK 保留 0 0 0 0
PINGREQ 保留 0 0 0 0
PINGRESP 保留 0 0 0 0
DISCONNECT 保留 0 0 0 0

DUP = 重复发送PUBLISH包

QoS = PUBLISH包消息质量

RETAIN = PUBLISH 保留标识

剩余长度

位置:第二个字节

剩余长度是指当前包中的剩余字节,包括可变包头的数据以及载荷。剩余长度不包含用来编码剩余长度的字节。

剩余长度怎么计算呢?说实话,我看了官方的描述很懵逼。但是看代码后就很清晰了。

占用字节 起始数值 结束数值
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)

下面是编码部分代码,可以直接放在—》C语言在线编辑器上试一下

#include <stdio.h>

int main(void) {  
    int encodedByte = 0;
    int X = 2097152;//想要进行编码的长度
    int index = 1;
    do{ 
        encodedByte = X % 128;
        X = X / 128;
        if ( X > 0 )
            encodedByte = encodedByte | 128;
        printf("编码第%d字节=%X(HEX)\n",index++,encodedByte);     
     }while ( X > 0 );
     
    return 0;
}

接下来是解码部分代码,也可以在—》C语言在线编辑器上试一下

#include <stdio.h>

int main(void) {  
    int multiplier = 1;
    int buff[4] = { 0x80,0x80,0x80,0x01};
    int value = 0;    
    int temp = 0;
    int index = 0;
    
    do{ 
        temp = buff[index++];//index先运算,再累加
        value += ( temp & 127) * multiplier;
        multiplier *= 128;
    }while((temp & 128) != 0 );
    
    printf("MQTT控制包长度%d字节",value);
	return 0;
}

三、可变包头

某些类型的MQTT控制包包含一个可变包头结构。位于固定包头和载荷之间。可变包头的内容取决于包的类型。可变包头中的包标识符字段在大多类型的包中比较常见。

数据包标识

Bit 7 6 5 4 3 2 1 0
byte1 包标识最高有效位
byte2 包标识最低有效位

许多控制数据包类型的可变报头组件都包含一个2字节的数据包标识符字段。这些控制数据包是PUBLISH(QoS> 0),PUBACK,PUBREC,PUBREL,PUBCOMP,SUBSCRIBE,SUBACK,UNSUBSCRIBE和UNSUBACK。

SUBSCRIBEUNSUBSCRIBEPUBLISH(在QoS> 0的情况下)控制包必须包含一个非零的16位包标识符 。每当客户端发送一个新的数据包(以上四种类型)时,客户端必须给该数据包分配一个当前未使用的数据包标识符。如果客户端重新发送一个特定的控制包,则它必须在该包的后续重新发送中使用相同的包标识符。在客户端处理了相应的确认数据包后,数据包标识符就可以重用。在QoS 1 PUBLISH的情况下,这是对应的PUBACK;在QoS 2的情况下,它是PUBCOMP。对于SUBSCRIBE或UNSUBSCRIBE,它是对应的SUBACK或UNSUBACK 。 当服务器发送QoS> 0 的PUBLISH时,同样的条件也适用于服务器。

如果其QoS值设置为0,则PUBLISH数据包不得包含数据包标识符。因为Qos=0时,是不会得到响应的。

PUBACK,PUBREC或PUBREL数据包必须包含与最初发送的PUBLISH数据包相同的数据包标识符。类似地,SUBACK和UNSUBACK必须包含分别在相应的SUBSCRIBE和UNSUBSCRIBE数据包中使用的数据包标识符。

控制包类型 是否包含标识符字段
CONNECT
CONNACK
PUBLISH 是(当Qos>0时)
PUBACK
PUBREC
PUBREL
PUBCOMP
SUBSCRIBE
SUBACK
UNSUBSCRIBE
UNSUBACK
PINGREQ
PINGRESP
DISCONNECT

客户端和服务端各自独立分配唯一标识。但是,一对客户端和服务端交换数据的时候可以使用相同的唯一标识。

四、载荷

有些MQTT控制包的最后一部分会包含载荷。其实负载就是想要传递的数据。

控制包类型 负载
CONNECT 必须
CONNACK
PUBLISH 可选(可以空载)
PUBACK
PUBREC
PUBREL
PUBCOMP
SUBSCRIBE 必须
SUBACK 必须
UNSUBSCRIBE 必须
UNSUBACK
PINGREQ
PINGRESP
DISCONNECT
 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服