zoukankan      html  css  js  c++  java
  • MQTT协议探究(一)

    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报文后
      • 必须丢弃任何与当前连接关联的未发布的遗嘱消息
      • 应该关闭网络连接,如果客户端还没有这么做
  • 相关阅读:
    VirtualBox Network设置的NAT和Bridged Adapter模式区别
    Kubernetes里的ConfigMap的用途
    使用Kubernetes里的job计算圆周率后2000位
    给谷歌输入法增添自定义词组,提高输入效率
    推荐一个yaml文件转json文件的在线工具
    GCC同时使用静态库和动态库链接
    Linux后台开发常用工具
    gcc链接参数--whole-archive的作用
    rdynamic和-whole-archive
    gcc和ld 中的参数 --whole-archive 和 --no-whole-archive
  • 原文地址:https://www.cnblogs.com/linzhanfly/p/9929529.html
Copyright © 2011-2022 走看看