MQTT 系列之 MQTT broker 的连接

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MQTT 系列之 MQTT broker 的连接相关的知识,希望对你有一定的参考价值。

参考技术A

client 在可以发布和订阅消息之前,必须先连接到 broker,下面我们来看一下连接到 broker 的流程。

连接的建立由 Client 端发起,Client 端首先向 broker 发送一个 CONNECT 数据包,CONNECT 数据包包含以下内容(这里我们略过 fixed header)。

在 CONNECT 数据包可变头中,含有以下信息。

协议名称(Protocol name) :值固定为 MQTT 字符。

协议版本 :对于 MQTT3.1.1 来说,值为 4.

用户名标识 :消息体中是否有用户名字段, 1bit , 0 或 1。

密码标识 :消息体中是否有密码字段,1bit,0 或 1。

遗愿消息 Retain 标志(will retain) :标识遗愿消息是否是 retain 消息,1 bit,0 或 1。

遗愿消息 QoS 标志 (will QoS) :标志遗愿消息的 QoS 是否存在,1 bit,0 或 1。

会话清除标志(clean session) :标识 Client 是否建立一个持久化的会话,1bit,0或1,当 clean session 的标识为 0 时,代表 client 希望建立一个之久的会话连接,broker 间存储该 client 订阅的主题和未接受的消息,否则broker不会存储这些数据,同时在建立连接时清除这个 client 之前的持久化会话保存的数据。

心跳保持(keep alive) :设置一个单位为秒的时间间隔,client 和 broker 之间在这个时间内至少需要进行一次消息交互,否则 client 和 broker 会认为它们之间的连接已断开。

CONNECT 数据包的消息体中包含了以下数据。

客户端标识符(client identifier) :Client Identifier 是用来标识 Client 身份的字段,在 MQTT3.1.1 的版本中,这个字段的长度是 1 到 23个字节,而且只能包含数字和26个字母(包括大小写),broker 通过这个字段来区分不同的 client。所有在连接的时候,client应该保证它的 identifier 是唯一的,通常我们可以使用比如 UUID,唯一的设备硬件标识,或者 android 设备的 DEVICE_ID 等作为 Client identifier 的取值来源。MQTT 协议中要求 Client 连接时必须带上 Client Identifier,但是也允许 broker 在实现时 Client Identifier 为空,这时 Broker 会为 Client 分配一个内部唯一的 Identifier。如果你需要使用持久化会话,那就必须自己为 Client 设定一个唯一的 Identifier。

用户名(Username) :如果可变头中的用户标识设为 1,那么消息体中将包含用户名字段,Broker 可以使用用户名和密码来对接入的 Client 进行验证,只允许已经授权的 Client 接入。注意不同的 Client 需要使用不同的 Client Identifier,但它们可以使用同样的用户名和密码进行连接。

密码(password) :如果可变头中的密码标识为1,那么消息体中将包含密码字段。

遗愿主题(will topic) :如果可变头中遗愿标识设为1,那么消息体中将包遗愿主题,当 Client 非正常地中断连接的时候,Broker将向指定的遗愿主题中发布遗愿消息。

遗愿消息(will message) :如果可变头中的遗愿标志为1,那么消息体中将包含遗愿消息,当 Client 非正常地中断连接的时候,Broker 将向指定的遗愿主题中发布由该字段指定的内容。

当 broker 收到 client 的 CONNECT 数据包之后,将检查并校验 CONNECT 数据包的内容,之后回复 Client 一个 CONNACK 数据包。
CONNACK 数据包包含以下内容(这里略过 Fixed header)。

CONNACK 数据包的可变头中,含有如下信息:
会话存在标识(Session Present Flag) :用于标识在 Broker 上,是否存在该 client(用 client identifier 区分)的持久性会话,1bit,0或1。当 Client 在连接时设置 clean session = 1 ,则 CONNACK 中的 Session Present Flag 始终为 0;当 client 在连接时设置 clean session = 0 时,那么分为两种情况:如果 broker 上面保存了这个 Client 之前留下的持久性会话,那么 CONNACK 中的 session present flag 值为 1,如果 broker 没有保存该 client 的任何会话数据,那么 CONNACK 中 session present flag 值为 0.

连接返回码: 用于标识 client 是否连接建立成功,连接返回码如下:

在这里强调一下 code 4 和 5。Return Code 4 在 MQTT 协议中的含义是 Username 和 Password 的格式不正确,但是在大部分的 Broker 实现中,在使用错误的用户名密码时,得到的返回码也是 4。所以这里我们认为 4 就是代表错误的用户名或密码。Return Code 5 一般在 Broker 不使用用户名和密码而使用 IP 地址或者 Client Identifier 进行验证的时候使用,来标识 Client 没有通过验证。

CONNACK 没有 payload。

Client 主动关闭连接的流程很简单,只需要向 broker 发送一个 DISCONNECT 数据包就可以了。DISCONNECT 数据包没有可变头和消息体。在 Client 发送完 DISCONNECT 后,无需等待 broker 的回复(broker 也不会有回复),直接关闭底层的 tcp 连接即可。

MQTT 协议规定 Broker 在没有收到 Client 的 DISCONNECT 数据包之前都应该保持和 Client 连接,只有 Broker 在 Keep Alive 的时间间隔里,没有收到 Client 的任何 MQTT 数据包的时候会主动关闭连接。一些 Broker 的实现在 MQTT 协议上做了一些拓展,支持 Client 的连接管理,可以主动地断开和某个 Client 的连接。

Broker 主动关闭连接之前不会向 Client 发送任何 MQTT 数据包,直接关闭底层的 TCP 连接就完事了。

以上是关于MQTT 系列之 MQTT broker 的连接的主要内容,如果未能解决你的问题,请参考以下文章

MQTT从入门到提高系列 | 06MQTT3.1.1之SUBSCRIBE订阅工作流

物联网之MQTT3.1.1和MQTT5协议 (20) MQTT 相关开源实现Server或Broker列表(会不断更新)

EMQ X 规则引擎系列 (八)桥接消息到 MQTT Broker

2019-07-13-mqtt-mosquitto系列14之保留消息retain

2019-07-13-mqtt-mosquitto系列14之保留消息retain

2019-07-13-mqtt-mosquitto系列14之保留消息retain