引言

书接上文网络编程——物联网利器MQTT通信协议详解(一) 系列文章链接:

四、MQTT协议原理

1、 MQTT协议的具体实现

MQTT协议基于发布/订阅模型,每一次通信都需要客户端和服务器端共同完成,在通讯过程中,MQTT协议三种核心角色:**发布者(Publisher)、代理服务器(Broker)、订阅者(Subscriber)消息(Message)**为基本传输单元,而MQTT传输的消息组成有:**主题(Topic)和负载(Payload)**两部分。

  • Topic——可以理解为消息的类型,订阅者订阅(Subscribe)后,Broker在接到这条Topic时就会自动转发到订阅者处,订阅者就会收到该主题的消息内容
  • Payload——可以理解为消息的内容,可以理解为消息真正的内容,就像HTTP POST方式通信时,Topic 相当于是URL,而Payload则相当于是HTTP请求包体部分。

MQTT会通过TCP/IP构建底层网络传输:它将建立客户端到服务器的连接,提供两者之间的一个有序的、无损的、基于字节流的双向传输,当应用数据通过MQTT网络发送时,MQTT会把与之相关的服务质量(QoS)和主题名(Topic)相关连。

2、 MQTT协议中的核心术语

2.1、订阅(Subscription)

既然是基于订阅/发布模型的,所谓订阅其实就和观察者模式中的订阅作用和概念相当,可以把Topic Filter看成订阅者的一个Key,Broker 转发时通过这个Key可以找到对应的订阅者完成转发。订阅后会与一个会话(Session)自动关联,而一个会话可以包含多个订阅且每一个会话中的每个订阅都有一个不同的Topic。

2.2、会话(Session)

一个有状态的客户端和服务端的交互,每个客户端与服务器建立连接后就是一个会话,有些会话的存续依赖于网络连接存在于一个网络之间,也可能在客户端和服务器之间跨越多个连续的网络连接。

2.3、主题(Topic )和 主题筛选器(Topic Filter)

**主题(Topic )和 主题筛选器(Topic Filter)**本质上就是一串通信各方约定的一定格式的字符串(),相当于是HTTP通信中的简化版的URL。其中主题主要是用于发布Topic时,而主题筛选器则是更多地用于订阅时(当然主题也可以应用于订阅),两者的区别在于主题筛选器(Topic Filter)可以包含通配符"+"(一个对主题名通配符筛选器,在订阅表达式中使用,表示订阅所匹配到的多个主题)。通信时Broker 会根据Topic 处理订阅和反订阅逻辑,以及根据Topic找到接收客户端,Broker才能将会将消息发送给订阅所匹配Topic的每个客户端。

  • 主题(Topic )——指附着于应用消息的标签,服务端用它来匹配订阅,服务端给每个匹配到的客户端发送一份应用信息的拷贝。
  • 主题筛选器——包含在订阅里的一个表达式,来表示一个或多个感兴趣的话题,主题筛选器可以包含通配符。

服务端不能用以通配符(#或+)开头的话题过滤器去匹配以$开头的话题名字

2.4、负载(Payload)

消息订阅者所具体接收的内容,相当于HTTP通信POST方式时的包体内容。

2.5、 MQTT协议中的主要方法

MQTT协议中定义了一些方法(也被称为动作),来于表示对确定资源(可以代表预先存在的数据或动态生成数据,通常指服务器上的文件或输出)所进行操作:

  • Connect——等待与服务器建立连接。
  • Disconnect——等待MQTT客户端完成所做的工作,并与服务器断开TCP/IP会话。
  • Subscribe——等待完成订阅。
  • UnSubscribe——等待服务器取消客户端的一个或多个topics订阅。
  • Publish——MQTT客户端发送消息请求,发送完成后返回应用程序线程。
2.6、MQTT控制包

通过网络连接发送的包含一定信息的控制包。MQTT规范定义了14个不同类型的控制包,其中一个(PUBLISH包)用来传输应用信息。

3、消息(Message)

消息(Message)指通过MQTT在网络中传输的应用程序数据。当应用消息通过MQTT传输的时候会附加上质量服务(QoS)和话题名称。

3.1、Message 和 Retained Message

MQTT 通信是通过Message 携带控制包进行通信的,通常若发布者将Message发布到某个Topic,却没有客户端订阅该主题,则Broker会简单地丢弃该消息。但发布者可以通过设置Retained Message标志来告诉Broker保留关于该主题的最后一条消息,当客户端再次上线时就会收到上次发送的最后一条消息,当Payload 为0字节时Broker 就会对服务器进行清空操作。需要注意的Retain Message 是指客户端发布时Retain 标记为true的Message。每个主题只保留一条消息,针对该主题发布的下一条消息将替换该主题的最后一条保留消息。若不需要,则应再下一次连接前主动清空服务器,来避免混淆。如果不使用清理会话,则可能会看到已存储但未设置保留的消息!

3.2、Broker 处理Retained Message

以下场景均是在客户端订阅之前先发布消息,

  • 以QoS=1发布未设置Retain的Message,新订阅者未收到消息
  • 以QoS=1发布Retain Message,新订阅者将接收到所对应的最后一条消息
  • 以QoS=1发布多条Retain Message,Payload依次为OFF,OFF2,OFF3,新的订阅者只得到最后一条消息OFF3

在这里插入图片描述

4、存储状态

客户端和服务端为了提供Quality of Service(QoS)的保障,存储Session状态是有必要的。客户端和服务端必须在整个Session期间都存储Session状态,只要有效的网络连接存在,Session就必须存在。

5、消息分发重试

当客户端将CleanSession设置为0进行重连,客户端和服务端都不许重发未确认的PUBLISH包(当QoS > 0时),只有PUBREL包使用原始包唯一标识,这是客户端和服务端被要求重发消息的唯一情况。

6、话题通配符

话题层级分隔符把层级结构引入到话题名称中。如果存在分隔符,话题名称会被分割为多个“话题层级”。一个订阅话题过滤器可以包含指定的通配符,通配符允许一次订阅多个话题。通配符可以被用在话题过滤器中,但不能用在话题名称里

6.1、话题层级分隔符/

斜杠(/)被用来分割话题书的每个层级,为话题名称提供一个分级结构。话题层级分割符的是有象征意义的,当订阅客户端指定的话题过滤器中遇到两个通配符的时候。话题层级分隔符可以唉话题名称或话题过滤器哦任何地方出现。相邻的层级分隔符标识一个零长度的话题层级。

6.2、单层级通配符+

加号(+ )通配符只能匹配单层话题。单层级通配符可以用在话题过滤器的任意层级,包括首层和末层。使用的时候必须占据整个层。可以在话题过滤器的多个层级使用,也可以和多层通配符联合使用。例如

  • “sport/tennis/+“匹配"sport/tennis/player1"和"sport/tennis/player2”,但是不匹配"sport/tennis/player1/ranking”。

而且因为单层级通配符只能匹配一个层级,所以"sport/+“不能匹配"sport”,但是可以匹配"sport/"。

  • "+"可用
  • "+/tennis/#"可用
  • "sprot+"不可用
  • "sport/+/player1"可用
  • “/finance"匹配”+/+“和”/+",但是不匹配"+"
6.3、 多层级通配符#

井号(#)匹配一个话题的任意数量的层级。多层级通配符代表父层级和任意数量的子层级。多层级通配符必须要么独自存在要么在话题层级分隔符之后。两种情况中都必须是话题过滤器的最后一个字符。如果客户端订阅“sport/tennis/player1/#”,使用下列话题名称的消息会被收到:

  • “sport/tennis/player1”
  • “sport/tennis/player1/ranking”
  • “sport/tennis/player1/score/wimbledon”
  • “sport/#” 也会匹配 “sport”,因为#包含父层级
  • "#"是可用的,而且会收到所有的应用消息
  • "sport/tennis/#"是可用的
  • "sport/tennis#"是不可用的
  • "sport/tennis/#/ranking"是不可用的

未完待续…

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐