美文网首页iOS进阶之路
MQTT教程(二):MQTT中的可变报头

MQTT教程(二):MQTT中的可变报头

作者: 康小曹 | 来源:发表于2019-04-17 16:41 被阅读36次

    上一章节中已经知道了MQTT中报文的基本结构:

    总结:

    • 固定报头:类似于人的名字,是一个代号信息
    • 可变报头:特异性信息
    • 负载:报文中的特异性信息的载体

    本文对控制报文的研究不涉及到socket编程,只研究报文大概的工作模式以理解MQTT的工作方式。Socket编程

    本章中主要介绍几个重点的报文格式,具体的socket实现可以参考文章。其他报文的格式大同小异,可以查阅官方文档


    CONNECT报文

    CONNECT报文有且只有一个,并且是客户端到服务端 建立连接 后的第一个报文,服务端必须将客户端发送的第二个CONNECT报文当作协议违规处理并断开客户端的连接。

    1.固定头部

    固定头部同前面说明的一样,包含报文类型和保留字段。具体格式如下:


    CONNECT报文固定头部
    2.可变头部

    CONNECT报文的可变报头按下列次序包含四个字段:

    • 协议名(Protocol Name)
    • 协议级别(Protocol Level)
    • 连接标志(Connect Flags)
    • 保持连接(Keep Alive)。
    2.1 协议名

    协议名是表示协议名 MQTT 的UTF-8编码的字符串。MQTT规范的后续版本不会改变这个字符串的偏移和长度。如果协议名不正确,服务端需要断开客户端的连接。

    协议名格式如下: CONNECT中的协议名
    2.2 协议级别

    协议级别通俗来讲就是协议的版本。

    客户端用8位的无符号值表示协议的修订版本。对于3.1.1版协议,协议级别字段的值是4(0x04)。如果发现不支持的协议级别,服务端必须给发送一个返回码为0x01(不支持的协议级别)的CONNACK报文响应CONNECT报文,然后断开客户端的连接。

    MQTT3.1.1的协议级别格式如下: 协议级别
    2.3 连接标志

    连接标志字节包含一些用于指定MQTT连接行为的参数。它还指出playload字段是否存在。

    连接标志的结构: 连接标志

    备注
    1.有效负载(playload)字段的存在与否并不是reserved字段来指定,而是will flag、user Name等字段。比如:如果will flag为1,则负载中需要包含will tpoic、will message等字段。如果需要用户名密码,则负载中需要包含这些信息。
    2.服务端必须验证CONNECT控制报文的保留标志位(第0位reserved)是否为0,如果不为0必须断开客户端连接

    所有连接标志的意义:

    标志明 位置 意义
    Clean Session 连接标志字节的第1位 告诉服务端是否需要基于客户端标识符,在对应的会话(session)中保存连接断开过程中收到的级别为Qos1和Qos2的消息并在连接恢复后想客户端进行分发
    Will Flag 连接标志的第2位 是否开启遗嘱消息模式,如果为YES,则服务端需要存储负载中客户端发送的will topic和will message
    Will Qos 连接标志的第4和第3位 遗嘱消息的安全级别,占用2byte,值为0、1、2
    Will Retain 连接标志的第5位 遗嘱消息是否需要作为保留消息发布
    Password Flag 连接标志的第6位。 是否需要密码
    User Name Flag 连接标志的第7位 是否需要用户名
    2.4 Keep alive

    是一个以秒为单位的最大时间间隔,表示为一个16位的字。
    其格式如下:


    keep alive

    备注:
    MSB表示最大有效为,LSB表示最小有效位。这里没有什么特殊含义,也不MSB也不表示正负,这里只是表示两个字节来描述Keep alive。至于官方文档中说明Keep Alive允许的最大值是18小时12分15秒,这是从2^16/3600=18.2044得出的

    Keep Alive说明:

    • 客户端负责保证控制报文发送的时间间隔不超过保持连接的值。如果没有任何其它的控制报文可以发送,客户端必须发送一个PINGREQ报文。不管保持连接的值是多少,客户端任何时候都可以发送PINGREQ报文,并且使用PINGRESP报文判断网络和服务端的活动状态。

    • 如果保持连接的值非零,并且服务端在一点五倍的保持连接时间内没有收到客户端的控制报文,它必须断开客户端的网络连接,认为网络连接已断开。

    • 客户端发送了PINGREQ报文之后,如果在合理的时间内仍没有收到PINGRESP报文,它应该关闭到服务端的网络连接。

    • 保持连接的值为零表示关闭保持连接功能。这意味着客户端不断开连接。

    备注:
    不管保持连接的值是多少,任何时候,只要服务端认为客户端是不活跃或无响应的,可以断开客户端的连接。

    至此,CONNECT报文的所有内容已经学习,最后用官方文档的CONNECT结构图来总结: CONNECT报文

    CONNACK报文

    CONNACK报文内容固定如下: CONNACK

    安全级别(Qos)

    安全级别主要应用在消息发布中,三种安全级别的消息发送机制如下:


    Qos

    Will Message

    MQTT中的遗嘱模式是什么:
    服务端或者客户端异常断开时,服务端需要将特定主题(will topic)的消息(will message)发送给订阅过该主题的客户端。

    遗嘱消息发布的条件,包括但不限于:

    • 服务端检测到了一个I/O错误或者网络故障。
    • 客户端在保持连接(Keep Alive)的时间内未能通讯。
    • 客户端没有先发送DISCONNECT报文直接关闭了网络连接。
    • 由于协议错误服务端关闭了网络连接。

    客户端正常的使用DISCONNECT报文断开连接的情况下,will message不会被发送。will message只用于客户端异常断开连接时,服务端发送一组特定主题(topic)的消息(message)


    RETAIN(保留消息)

    什么是保留机制:
    简而言之就是客户端告诉这条消息是否需要分发给之后建立连接的新客户

    保留消息的工作机制:


    RETAIN消息的工作机制

    注意:

    • 图中retain=1,qos=0的情况,此时服务端需要清空该topic的所有消息
    • retain后的qos为0的消息仍然会发送,只是发送机制不同于Qos1和Qos2,具体见下一章节。
    • 保留消息不是服务端会话状态的一部分,会话终止时不能删除保留消息,服务端应该保留那种消息直到客户端删除它。(如何删除:客户端发送RETAIN=1 Qos=0的消息)

    疑问:
    如果will message的retain标志位1。当客户端正常disconnect时,服务端删除的是服务端存储的will message还是session中的will message?也就是说,正常断开连接后,如果另外一个client建立了一个新的连接并订阅了那个will topic,此时该client是否能收到will message?
    初步结论:通过retain和will的设计目的来讲,当正常DISCONNECT时,服务端会删除服务端保存的will message,也就是新进的client不会收到这个已删除的will message

    相关文章

      网友评论

        本文标题:MQTT教程(二):MQTT中的可变报头

        本文链接:https://www.haomeiwen.com/subject/oruuwqtx.html