MQTT协议详解

发布时间:2023年12月26日

MQTT协议详解

简介

mqtt属于应用层协议,在tcp上层,mqtt协议中的用户角色分为两类mqtt_broker(中心转发)、mqtt_client(pub/sub)。
这两者之间的消息交互分为如下几类:连接/断开服务器、订阅/取消订阅、发布消息、心跳。

连接/断开broker

在这里插入图片描述

  1. client和broker建立tcp连接;
  2. 连接场景下包含两种应用层消息格式:CONNECT、CONNACK;
  3. 客户端超时机制协议中并未详细说明,一般由客户端通过简单的超时重传实现;
  4. 一旦收不到CONNACK,重新建立tcp连接,并重新发起CONNECT。

CONNECT报文的可变报文头按下列次序包含四个字段:协议名、协议级别、连接标志、保持连接。

连接标志
在这里插入图片描述
清理会话 Clean Session:
指定会话状态处理方式,客户端和服务端可以保存会话状态,以支持跨网络连接的可靠消息传输。
设置为 0:当连接断开后,客户端和服务端必须保存会话信息,以便重新连接后使用。
设置为 1:当连接断开后,丢弃之前会话信息。
这里的会话信息涉及到很多状态,比如:

客户端的会话状态:

  • 已经发送给服务端,但是还没有完成确认的 QoS 1 和 QoS 2 级别的消息;
  • 已经从服务端接收,但是还没有完成确认的 QoS 2 级别的消息。

服务端的会话状态:

  • 客户端订阅信息;
  • 已经发送给客户端,但是还没有完成确认的消息 QoS 1 和 QoS 2 级别的消息。
  • 即将传输给客户端的 QoS 1 和 QoS 2 级别的消息。
  • 已从客户端接收,但是还没有完成确认的 QoS 2 级别的消息。
  • 可选,准备发送给客户端的 QoS 0 级别的消息。

遗嘱标志 Will Flag:
遗嘱标志被设置为 1,表示如果连接请求被接受了,遗嘱(Will Message)消息必须被存储在服务端并且与这个网络连接关联。之后网络连接关闭时,服务端必须发布这个遗嘱消息,除非服务端收到 DISCONNECT 报文时删除了这个遗嘱消息 。
遗嘱消息发布的条件,包括但不限于:

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

遗嘱 QoS Will QoS:
这两位用于指定发布遗嘱消息时使用的服务质量等级。

遗嘱保留 Will Retain:
当客户端连接断开,遗嘱消息发布后,该消息会保留在服务器上。这样,任何在此后订阅相应主题的客户端,都能收到这条遗嘱消息,了解到该客户端已经下线的信息。这对于需要监控设备或用户在线状态的应用来说非常有用。

用户名标志 User Name Flag:
标识 payload 中是否需要包含用户名。

密码标志 Password Flag:
标识 payload 中是否需要包含密码信息。

保持连接 Keep Alive:
保持连接是一个以秒为单位的时间间隔,它是指在客户端传输完成一个控制报文的时刻到发送下一个报文的时刻,两者之间允许空闲的最大时间间隔。客户端负责保证控制报文发送的时间间隔不超过保持连接的值。
如果设置了保持连接,并且客户端在这个时间内并未发送任何报文,服务端可以断开客户端连接。

CONNECT 报文的有效载荷(payload)包含:客户端标识符、遗嘱主题、遗嘱消息、用户名、密码。通过上面说的包头中连接标志来决定是否包含这些字段。

客户端标识符
用于识别连接到 MQTT 服务器的客户端。每个客户端在连接一个目标服务器里都必须具有唯一的标识符,以便服务器可以区分它们。
如果两台设备都使用相同的客户端标识符,则会造成之后上线的设备连接服务器后,服务器将主动断开前一台设备的连接。

断开连接
DISCONNECT:表示客户端正常断开连接,服务端收到后需要清理与当前连接相关的未发布的遗嘱消息。

订阅/取消订阅主题

在这里插入图片描述
SUBSCRIBE报文的有效荷载包含了主题过滤器列表、qos。

  • 主题过滤器列表标识客户端想要订阅的主题;
  • qos表示服务器向客户端发送应用消息所允许的最大qos等级。

发布消息

PUBLISH控制报文是指从客户端向服务器或者服务器向客户端发送一个应用消息,其实从服务器分发的报文给订阅者也属于PUBLISH控制报文。
**注意:**不同的qos,publish控制报文的处理方式也不同,publish和subscribe这两个消息中都会带qos,mqtt协议规定:无论是发布消息的qos等级还是订阅消息的qos等级,实际的qos等级都会以两者中的最小值为准。

qos等级:
在这里插入图片描述

qos0的publish控制报文

qos0代表消息的分发依赖于底层网络的能力,服务器不会发送响应,发布者也不会重试,它在发出这个消息的时候就会立马将消息丢弃,这个消息可能送达一次也可能根本没送达。
在这里插入图片描述

qos1的publish控制报文

qos1表示服务质量确保消息至少送达一次,甚至可能被多次处理。qos1的publish报文的可变报文头中包含一个报文标识符,需要PUBACK报文确认。
在这里插入图片描述
qos1的场景会带来什么问题?
消息重复处理,比如发送了publish消息,并且接收端也回复了puback,但是由于网络原因,puback晚到了,导致发送端由于timeout重新触发了publish消息,这个时候接收端仍旧会处理这条重复的publish消息。

qos2的publish控制报文

qos2表示消息既不丢失也不会重复。
在这里插入图片描述
为啥需要类似四次握手才能保证消息不丢失也不会重复?

我们先看只采用两次交互:
在这里插入图片描述

两次交互如何保证消息不丢失不重复?

  • 消息不丢失依赖puback,pub在timeout间隔内收不到puback,就会重新触发publish消息;
  • 消息不重复依赖接收端保存msg,msg中存在msg_id,当消息重复推送时,可以在接收端相应去重,做到只接收一次。

两次交互的缺点:

  • sub端没有释放msg,因为sub端不知道server是否收到了puback消息,所以需要一直保存msg,来实现对server端超时重发的msg去重;
  • msg_id存在被覆盖的可能,mqtt协议规定msg_id占两个byte,也就是65535个,如果sub一直不删除本地msg,可能会导致msg_id被覆盖。
    所以两次交互肯定不够,起码得再需要一次交互告诉sub删除本地msg。

采用三次交互:
在这里插入图片描述
三次交互的缺点:
release消息无法保证一定能被server和sub接收到,因此还需要一次响应来保证server、sub接收到release消息。

采用四次交互:
在这里插入图片描述

四次交互在三次交互基础上增加了一个pubcomp包,当pub与server收到pubcomp包后,表示接收端已经收到release包了,可以删除msg了。到此qos2实现了包的去重与msgid的可重用。

心跳

mqtt协议规定了PINGREQ和PINGRESP消息类型,用于实现心跳机制。PINGREQ消息是由客户端向服务器发送的心跳包,PINGRESP是服务器回复的心跳包确认消息。
在这里插入图片描述
在mqtt协议中,PINGREQ是在一段时间内没有任何其他报文交互时才会发送,这个机制类似内核tcp层的keepalive。
当客户端和服务器建立连接时,会设定一个keepalive的时间间隔,如果在这个时间间隔内,客户端没有发送或接收任何其他报文,那么就会发送一个PINGREQ到服务器,以保持连接的活跃。
所以PINGREQ并不是定时发送,而是在没有其他报文交互的情况下才会发送,以此来保持与服务器的连接。

文章来源:https://blog.csdn.net/SWX230162/article/details/135230443
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。