Mqtt通信协议详解

文章目录

  • 1. 简介mqtt
  • 2.mqtt协议实现
  • 3.Mqtt数据包
  • 4. QoS等级
  • 5. mqtt传输安全保证
    • 5.1 应用层
    • 5.2 传输层
      • 5.2.1 TLS安全协议
    • 5.3 网络层

1. 简介mqtt

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的“轻量级”通讯协议,该协议构建于TCP/IP协议上。

2.mqtt协议实现

  • mqtt实现:需要客户端和服务端,不同的客户端通过服务端来获取消息,服务端相当于是个中转站,与各个客户端相连
    Mqtt通信协议详解_第1张图片

  • 实现MQTT协议需要客户端和服务器端通讯完成,在通讯过程中,MQTT协议中有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。
    MQTT传输的消息分为:主题(Topic)和负载(payload)两部分:
    (1)Topic,可以理解为消息的类型,订阅者订阅(Subscribe)后,就会收到该主题的消息内容(payload);
    (2)payload,可以理解为消息的内容,是指订阅者具体要使用的内容。

  • 不同的客户端在连接中转站MqttBroker 之后,每个客户端都可以发布和订阅主题,主题就是客户端发布内容的名称,如A客户端发布主题名 11,内容为 nihao , 客户端就可以B订阅A的主题名11来获取A发布的内容 nihao,同理B也可以订阅A的主题获取内容。

3.Mqtt数据包

一个MQTT协议数据包由固定头(Fixed header),可变头(Variable Header),消息体(Payload)三部分组成。
1
. 固定头
:固定头存在于所有的MQTT数据包中,表示数据包类型及数据包的分组类标识。其结构如下:
Mqtt通信协议详解_第2张图片
1.1 mqtt数据包类型:位于Byte1的第7~4位
Mqtt通信协议详解_第3张图片
1.2 标识位:位于Byte1的第3~0位,在不使用标识位的消息类型中,标识位被做为保留位。如果收到无效的标志时,接收端必须关闭网络连接。
Mqtt通信协议详解_第4张图片
DUP:

发布消息的副本。用来在保证消息的可靠传输,如果设置为1,则在下面的变长中增加Messageld,并且需要回复确认,以保证消息传输完成,但不能用于检测消息重复发送。

QoS:

发布消息的服务质量,即:保证消息传递的次数。

RETAIN:

发布保留标识,表示服务器要保留这次推送的信息,如果有新的订阅者出现,就把这消息推送给它,如果设有那么推送至当前订阅者后释放。

1.3 剩余长度(Remaining Length)

固定头的第二字节用来保存变长头部和消息体的总大小的,但不是直接保存的。这一字节是可以扩展,其保存机制,前7位用于保存长度,后一部用做标识。当最后一位为 1时,表示长度不足,需要使用二个字节继续保存。

2 可变头
可变头存在于部分MQTT数据包中,数据包类型决定了可变头是否存在及其具体内容。它驻位于固定的头和负载之间。
3.消息体
消息体存在于部分的MQTT数据包中,表示客户端收到的具体内容。
Payload消息体位MQTT数据包的第三部分,CONNECT、SUBSCRIBE、SUBACK、UNSUBSCRIBE四种类型的消息 有消息体:
CONNECT,消息体内容主要是:客户端的ClientID、订阅的Topic、Message以及用户名和密码。

SUBSCRIBE,消息体内容是一系列的要订阅的主题以及QoS。

SUBACK,消息体内容是服务器对于SUBSCRIBE所申请的主题及QoS进行确认和回复。

UNSUBSCRIBE,消息体内容是要订阅的主题。

4. QoS等级

有三种消息发布服务质量:
QoS 是消息的发送方(Sender)和接受方(Receiver)之间达成的一个协议:

  • QoS0: “至多一次”,消息发布完全依赖底层TCP/IP网络。会发生消息丢失或重复。Sender 发送的一条消息,Receiver 最多能收到一次,也就是说 Sender 尽力向 Receiver 发送消息,如果发送失败,也就算了;
    如下:Sender向Receiver发送一个包含消息数据的PUBLISH包,然后不管结果如何,丢掉已发送的PUBLISH包,一条消息的发送完成。
    Mqtt通信协议详解_第5张图片

  • QoS1: “至少一次”,确保消息到达,==所以有一个应答的机制。==但消息重复可能会发生。Sender 发送的一条消息,Receiver 至少能收到一次,也就是说 Sender 向 Receiver 发送消息,如果发送失败,会继续重试,直到 Receiver 收到消息为止,但是因为重传的原因,Receiver 有可能会收到重复的消息;
    如下图:Sender向Receiver发送一个带有数据的PUBLISH包,并在本地保存这个PUBLISH包;Receiver收到PUBLISH包以后,向Sender发送一个PUBACK数据包,PUBACK数据包没有消息体(Payload),在可变头中有一个包标识(Packet Identifier),和它收到的PUBLISH包中的Packet Identifier一致。Sender收到PUBACK之后,根据PUBACK包中的Packet Identifier找到本地保存的PUBLISH包,然后丢弃掉,一次消息的发送完成。

Mqtt通信协议详解_第6张图片
问题:

  • 如果Sender在一段时间内没有收到PUBLISH包对应的PUBACK,它将该PUBLISH包的DUP标识设为1(代表是重新发送的PUBLISH包),然后重新发送该PUBLISH包。
  • Receiver可能会重复收到消息,需自行去重。

QoS2: “只有一次”,确保消息到达一次。Sender 发送的一条消息,Receiver 确保能收到而且只收到一次,也就是说 Sender 尽力向 Receiver 发送消息,如果发送失败,会继续重试,直到 Receiver 收到消息为止,同时保证 Receiver 不会因为消息重传而收到重复的消息。
如下:

  1. Sender发送QoS为2的PUBLISH数据包,数据包 Packet Identifier 为 P,并在本地保存该PUBLISH包;
  2. Receiver收到PUBLISH数据包后,在本地保存PUBLISH包的Packet Identifier P,并回复Sender一个PUBREC数据包,PUBREC数据包可变头中的Packet Identifier为P,没有消息体(Payload);
  3. 当Sender收到PUBREC,它就可以安全的丢弃掉初始Packet Identifier为P的PUBLISH数据包。同时保存该PUBREC数据包,并回复Receiver一个PUBREL数据包,PUBREL数据包可变头中的Packet Identifier为P,没有消息体;
  4. 当Receiver收到PUBREL数据包,它可以丢掉保存的PUBLISH包的Packet Identifier P,并回复Sender一个可变头中 Packet Identifier 为 P,没有消息体(Payload)的PUBCOMP数据包;
  5. 当Sender收到PUBCOMP包,那么认为传输已完成,则丢掉对应的PUBREC数据包;
    Mqtt通信协议详解_第7张图片
    上面是一次完整无误的传输过程,然而传输过程中可能会出现以下情况:
  • 情况1:Sender发送PUBLISH数据包给Receiver的时候,发送失败;
  • 情况2:Sender已经成功发送PUBLISH数据包给Receiver了,但是Receiver发送PUBREC数据包失败;
  • 情况3:Sender已经成功收到了PUBREC数据包,但是PUBREL数据包发送失败;
  • 情况4:Receiver已经收到了PUBREL数据包,但是发送PUBCOMP数据包时发送失败

针对上述的问题,较为详细的处理方法如下:

  • 不管是情况1还是情况2,因为Sender在一定时间内没有收到PUBREC,那么它会把PUBLISH包的DUP标识设为1,重新发送该PUBLISH数据包;
  • 不管是情况3还是情况4,因为Sender在一定时间内没有收到PUBCOMP包,那么它会重新发送PUBREL数据包;
  • 针对情况2,Receiver可能会收到多个重复的PUBLISH包,更加完善的处理如下:
    Receiver在收到PUBLISH数据包之后,马上回复一个PUBREC数据包。并会在本地保存PUBLISH包的Packet Identifier P,不管之后因为重传多少次这个Packet Identifier 为P的数据包,Receiver都认为是重复的,丢弃。同时Receiver接收到QoS为2的PUBLISH数据包后,并不马上投递给上层,而是在本地做持久化,将消息保存起来(这里需要是持久化而不是保存在内存)。
  • 针对情况4,更加完善的处理如下:
    Receiver收到PUBREL数据包后,正式将消息递交给上层应用层,投递之后销毁Packet Identifier P,并发送PUBCOMP数据包,销毁之前的持久化消息。之后不管接收到多少个PUBREL数据包,因为没有Packet Identifier P,直接回复PUBCOMP数据包即可。

注意:
QoS是Sender和Receiver之间的协议,而不是Publisher和Subscriber之间的协议。换句话说,Publisher发布了一条QoS1的消息,只能保证Broker能至少收到一次这个消息;而对于Subscriber能否至少收到一次这个消息,还要取决于Subscriber在Subscibe的时候和Broker协商的QoS等级。

5. mqtt传输安全保证

5.1 应用层

MQTT还提供客户标识(Client Identifier)以及用户名密码,在应用层验证设备,通过在mqttbroker 设置用户名和密码,客户端连接时需要输入相应的用户名和密码

5.2 传输层

传输层:传输层使用SSL/TLS加密是确保安全的一个好手段,可以防止中间人攻击(Man-In-The-Middle Attack)。客户端证书不但可以作为设备的身份凭证,还可以用来验证设备。使用 SSL(升级版本 TLS)对网络数据进行加密(这与 MQTT 协议本身是无关的,会增加网络开销
SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。

  • 以下是设置MQTT的TLS加密的基本步骤:
  1. 生成或获取MQTT代理的服务器证书和私钥。

  2. 配置MQTT代理以使用服务器证书和私钥。

  3. 为每个MQTT客户端生成或获取客户端证书和私钥。

  4. 配置MQTT客户端以使用客户端证书和私钥。

  5. 配置MQTT代理以要求所有客户端连接使用TLS加密。

  6. 配置MQTT客户端以使用TLS加密连接到代理。

5.2.1 TLS安全协议

由于TLS对交互信息的时序有规定,所以下层协议必须能够提供这种时序服务,因此TLS不能使用UDP来传输。
TLS 1.3协议层级架构:
Mqtt通信协议详解_第8张图片
同样在TLS协议内部也是基于分层架构,分为两层:下层为记录层协议,为TLS上层子协议为传送提供分片、消息加密及加密后报传输,同时对接收到的数据进行验证、解密、重新组装,然后提交给高层的应用层;上层包含4种子协议:==握手协议(Handshake Protocal)、警报协议(Alert Protocol)、应用数据协议(Application Protocol)及Change_cipher_spec。==其中change_cipher_spec只是为了兼容性存在,其余每个子协议都具有特定的作用,组合起来实现完整的协议功能。

  • 握手协议
    握手协议如字面所言,是在加密通信之前,对于加密使用的算法套件及加密密钥进行协商。
    1、 通过ClientHello及ServerHello完成了随机数、加密算法包及证书格式的协商,重点完成了密钥参数的传输

    2、 通过Certificate及CertificateVerify应用证书体系及数字签名完成身份认证

    3、 通过AEAD对称加密算法,完成握手消息中数据加密

  • Alert Protocol
    报警协议也如字面含义所示,是用来指示关闭信息和错误信息的,相应的主要包含两大类:关闭警报和错误警报。
    Mqtt通信协议详解_第9张图片

  • Record Protocol
    如上面综述所言,记录层位于TLS内部下层,主要负责验证、分片/重组、加密/解密的任务。

    a) 加密/解密:这个就比较显而易见了,不做过多解释;
    b) 分片/重组:这里的分片不是由于下层协议的帧长度限制的,而是因为解密方需要收完整个record,才能解密。长度过长会增大延迟,因此TLS协议规定length必须小于 2^14字节;
    c) 验证:这部分内容涉及比较多,包括报文时序是否满足协议规定,AEAD中的消息认证是否正确,填充是否正确等内容。

5.3 网络层

网络层:有条件可以通过拉专线或者使用VPN来连接设备与MQTT代理,以提高网络传输的安全性。

你可能感兴趣的:(mqtt,服务器,网络)