操作行为
4.1 状态存储 Storing state
Storing state
客户端和服务端必须存储会话状态以保证服务质量。==客户端和服务端必须
在会话持续的所有时间内都存储会话状态。==[MQTT-4.1.0-1]。==只要有活动的网络连接,会话就必须保持。== [MQTT-4.1.0-2]
保留消息不构成服务器中会话状态的一部分。服务端应该
保留这些消息直到客户端删除它。
非规范性注解 客户端和服务端的存储容量必然是有限的,还可能要受管理策略的限制,比如会话状态在网络连接之间的最大存储时间。包括对定义条件的自动响应在内的管理员级别的操作可以丢弃已经存储的会话状态,这会造成会话终止。这些操作可能是由资源限制或其他操作原因引发的。请慎重的评估客户端和服务端的存储容量以确保它们是充足的。 非规范性注解 硬软件故障可能会对客户端或服务端存储的会话状态造成数据损坏或者丢失。 非规范性注解 服务器和客户端操作正常可能意味着,已保存的状态丢失或损坏是管理操作或软硬件故障造成的。管理操作可能是对某个预定义条件的自动响应。这些操作可能是资源限制或其他操作原因引发的。例如,服务端可能会基于外部条件,决定不再将某个消息或某些消息分发给任何当前的或以后的客户端。 非规范性注解 MQTT用户应该评估MQTT客户端和服务端实现的存储容量,确保能满足需求。
4.1.1 非规范示例 Non normative example
Non normative example
例如,想要收集电表读数的用户可能会决定使用QoS 1等级的消息,因为他们需要防止数据在网络传输中丢失。但是,他们可能已经却确定电源数据是足够可靠的,所以客户端和服务端的数据可以存储在易失性存储器中而不存在太大丢失风险。
与之相反,停车计费支付应用的提供商可能要求任何情况下都不能让支付信息丢失。因此他们要求在通过网络传输之前,所有的数据必须强制写入非易失性存储器中。
4.2 网络连接 Network Connections
Network Connections
MQTT协议需要一个能提供有序、无损、双向字节流的底层传输协议。
非规范性注解 MQTT3.1使用的传输协议是 [RFC793] 定义的TCP/IP。TCP/IP也可用于MQTT 3.1.1。下面的协议也支持:
非规范性注解 IANA注册了TCP的8883和1883端口,分别用于MQTT的TLS和非TLS通信。
像用户数据报协议(UDP)一样的无连接网络传输协议是不合适的,因为它们可能会丢失或者重排序数据。
4.3 服务质量等级和协议流程 Quality of Service levels and protocol flows
Quality of Service levels and protocol flows
MQTT按照这里定义的服务质量 (QoS) 等级分发应用消息。分发协议是对称的,在下面的描述中,客户端和服务端既可以是发送者也可以是接收者。分发协议仅涉及从单个发送者到单个接收者的应用消息。服务端分发应用消息给多个客户端时,每个客户端独都是独立处理。分发给客户端的出站应用消息和入站应用消息的QoS等级可能是不同的。
下面的非规范流程图展示了可能的实现方法。
4.3.1 QoS 0:最多交付一次
消息依赖于底层网络的功能进行传递。接收者不会发送响应,发送者也不会重试。消息可能送达一次也可能根本没送达。
==对于QoS 0的分发协议,发送者==
==
必须
发送QoS等于0,DUP等于0的PUBLISH
报文 [MQTT-4.3.1-1]==。
对于QoS 0的分发协议,接收者
接受
PUBLISH
报文时同时接受消息的所有权。
图例 4.1 – 非规范示例的QoS 0协议流程图,
发送者操作 Sender Action
控制报文 Control Packet
接收者操作 Receiver Action
PUBLISH
QoS 0, DUP=0
---------->
将应用消息分发给合适的收件人 Deliver Application Message to appropriate onward recipient(s)
4.3.2 QoS 1: 至少交付一次
该服务质量等级确保消息至少送达一次。QoS 1的PUBLISH
报文的可变报头中包含一个报文标识符,需要PUBACK
报文确认。第2.3.1节提供了有关报文标识符的更多信息。
==在QoS 1的分发协议中,发送者==
==每次发送新的应用消息都
必须
分配一个未使用的报文标识符。====发送的
PUBLISH
报文必须
包含QoS=1,DUP=0的报文标识符。====
必须
将这个PUBLISH
报文看作是“尚未确认的” ,直到从接收者那收到对应的PUBACK
报文。4.4节有一个关于未确认消息的讨论。== [MQTT-4.3.2-1]
一旦发送者收到PUBACK
报文,该报文标识符就可以重用。
注意:允许发送者在等待确认时使用不同的报文标识符发送后续的PUBLISH
报文。
==对于QoS 1的分发协议,接收者==
==
必须
使用PUBACK
报文响应。该报文包含传入的的PUBLISH
报文的报文标识符并已经接管了应用消息的所有权。====发送了
PUBACK
报文之后,接收者必须将任何包含相同报文标识符的入站PUBLISH
报文当作一个新的发布消息,无论它的DUP的设定值。==[MQTT-4.3.2-2].
图例 4.2 – QoS 1协议流程图,非规范示例
发送者操作 Sender Action
控制报文 Control Packet
接收者操作 Receiver Action
存储消息 Store message
Send PUBLISH QoS 1, DUP 0,
---------->
<----------
开始传送应用消息1 Initiate onward delivery of the Application Message1
丢弃消息 Discard message
1在发送PUBACK
之前,接收者不需要完成应用消息的分发。原来的发送者收到PUBACK
报文之后,应用消息的所有权就会转移给这个接收者。
4.3.3 QoS 2: 恰好分发一次
这是最高等级的服务质量,适用于消息既不能丢失也不能重复的情况。使用这个服务质量等级会带来额外的开销。
QoS 2的消息可变报头中有报文标识符。第2.3.1节提供了有关报文标识符的更多信息。QoS 2等级的PUBLISH
报文的接收者使用两步确认过程来确认接收。
==在QoS 2的分发协议中,发送者==
==
必须
给要发送的新应用消息分配一个未使用的报文标识符。====发送的
PUBLISH
报文包含QoS = 2,DUP = 0的数据包标识符====
必须
将这个PUBLISH
报文看作是未确认的
,直到从接收者那收到对应的PUBREC
报文。有关未确认消息的详细内容请参见第4.4节。====收到
PUBREC
报文后必须
发送一个PUBREL
报文。PUBREL
报文必须包含与原始PUBLISH
报文相同的报文标识符。====
必须
将这个PUBREL
报文看作是未确认的
,直到从接收者那收到对应的PUBCOMP
报文。====一旦发送了对应的
PUBREL
报文就不能
重发这个PUBLISH
报文。==
[MQTT-4.3.3-1].
一旦发送者收到PUBCOMP
报文,这个报文标识符就可以重用。
注意:允许发送者在等待服务端确认时使用不同的报文标识符发送后续的PUBLISH
报文。
==对于QoS 2的分发协议,接收者==
==
必须
使用PUBREC
报文响应。该报文包含传入的的PUBLISH
报文的报文标识符并已经接管了应用消息的所有权。====在收到对应的
PUBREL
报文之前,接收者必须
发送PUBREC
报文确认后续是否有任何具有相同标识符的PUBLISH
报文。 在这种情况下,它不能
重发消息给之前的接收者。====响应
PUBREL
报文的PUBCOMP
报文必须
包含与PUBREL
报文相同的标识符。====发送
PUBCOMP
报文之后,接收者必须将包含相同报文标识符的任何后续PUBLISH
报文当作一个新的发布。==
[MQTT-4.3.3-2].
图例4.3-非规范示例的QoS2协议流程图
发送者操作 Sender Action
控制报文 Control Packet
接收者操作 Receiver Action
存储消息 Store message
PUBLISH QoS 2, DUP 0
---------->
存储消息或存储报文标识符之后发起之前应用消息的分发 Method A, Store message or Method B, Store then Initiate onward delivery of the Application Message1
PUBREC
<----------
丢弃消息,存储收到的PUBREC报文的报文标识符 Discard message, Store PUBREC received
PUBREL
---------->
---------->
发起应用消息的分发之后丢弃消息或者丢弃收到报文标识符 Method A, Initiate onward delivery of the Application Message1 then discard message1 or Method B, Discard
Send PUBCOMP
<----------
丢弃消息状态 Discard stored state
1 不要求接收者在发送PUBREC
或PUBCOMP
之前完成分发应用消息。原始发送者收到PUBREC
报文之后,应用消息的所有权就会转移给这个接收者。 >
图例4.3–QoS 2协议流程图,非规范示例 展示了接收者对QoS 2等级消息的两种处理方法。他们的区别是消息开始后续分发的时间点不同。两种方法都是特定与不同实现方法的。只要选择两种中一种就不会影响QoS2级别的流程的进行。
4.4 消息分发重试 Message delivery retry
Message delivery retry
==清理会话标志为0的客户端重连时,客户端和服务端必须
使用原始的报文标识符重发任何未确认的PUBLISH
报文(如果QoS>0)和PUBREL
报文== [MQTT-4.4.0-1]。这是唯一要求
客户端或服务端重发消息的情况。
非规范性注解 由于历史原因,需要重发控制报文才能解决某些早期TCP网络的数据丢包问题。部署在这些环境中的MQTT 3.1.1时,可能仍然需要关注这个问题。
4.5 消息收到 Message receipt
Message receipt
==服务端接管入站应用消息的所有权时,它必须
将消息添加到匹配订阅的客户端的会话状态中。匹配规则定义见第4.7节== [MQTT-4.5.0-1]。
正常情况下,客户端会收到对它发出的订阅的响应消息。客户端也可能会收到不匹配它的订阅的消息。如果服务端自动给客户端分配了一个订阅,可能发生这种情况。客户端正在处理UBSUBSCRIBE
请求时也可能收到消息。==客户端必须
按照可用的QoS规则确认它收到的PUBLISH
报文,不论它是否选择处理报文包含的应用消息== [MQTT-4.5.0-2]。
4.6 消息排序 Message ordering
Message ordering
==实现本章定义的协议流程时,客户端必须
遵循下列规则:==
==重发任何
PUBLISH
报文时,必须
按原始PUBLISH
报文的发送顺序重发(适用于QoS 1和QoS 2消息)==[MQTT-4.6.0-1]。==
必须
按照对应的PUBLISH
报文的顺序发送PUBACK
报文(QoS 1消息)==[MQTT-4.6.0-2]。==
必须
按照对应的PUBLISH
报文的顺序发送PUBREC
报文(QoS 2消息)==[MQTT-4.6.0-3]。==
必须
按照对应的PUBREC
报文的顺序发送PUBREL
报文(QoS 2消息)== [MQTT-4.6.0-4]。
==服务端必须
默认每个主题都是“有序主题”。它可以
提供一个管理或其它机制,以允许将一个或多个主题当作是“无序主题”== [MQTT-4.6.0-5]。
==服务端处理发送给有序主题的消息时,必须
遵循上面的规则将消息分发给每个订阅者。此外,它必须
按照从客户端收到的顺序发送PUBLISH
报文给消费者(对相同的主题和QoS)==[MQTT-4.6.0-6]。
非规范性注解 上面列出的规则确保,使用QoS 1发布和订阅的消息流,订阅者按照消息发布时的顺序收到每条消息的最终副本,但是消息可能会重复,这可能导致在它的后继消息之后收到某个已经收到消息的重发版本。例如,发布者按顺序1,2,3,4发送消息,订阅者收到的顺序可能是1,2,3,2,3,4。 如果客户端和服务端能保证任何时刻最多有一条消息在“正在传输中”(在某条消息被确认前不发送后面的那条消息),则就不会有QoS 1的消息会在它的任何后续消息之后收到。 例如,订阅者收到的顺序可能是1,2,3,3,4,而不是1,2,3,2,3,4。将传输窗口设为1意味着,在同一个主题上,即使发布者发送了一系列不同QoS等级的消息,它们的顺序也被保留。
4.7 主题名和主题过滤器 Topic Names and Topic Filters
Topic Names and Topic Filters
4.7.1 主题通配符 Topic wildcards
Topic wildcards
主题级别分隔符用于使主题名结构化。如果存在分隔符,它将主题名分割为多个“主题级别” 。
订阅的主题过滤器可以包含特殊的通配符,允许你一次订阅多个主题。
==主题过滤器中可以使用通配符,但是主题名不能
使用通配符== [MQTT-4.7.1-1]。
4.7.1.1 主题级别分隔符 Topic level separator
Topic level separator
正斜杠(‘/’ U+002F)用于分隔主题的每个级别,并为主题名提供一个分层结构。当订阅客户端指定的主题过滤器遇到两组通配符中任意一组时,使用主题级别分隔符就显得十分中重要了。主题级别分隔符可以出现在主题过滤器或主题名的任何位置。相邻的主题层次分隔符表示一个零长度的主题级别。
4.7.1.2 多级通配符 Multi-level wildcard
Multi-level wildcard
数字标志(‘#’ U+0023)是可以匹配主题中任意级别的通配符。多级通配符可以表示父级和任意数量的子级别。==多级通配符必须
位于它自己的级别或者跟在主题级别分隔符后面。不管哪种情况,它都必须
是主题过滤器的指定的最后一个字符== [MQTT-4.7.1-2]。
非规范性注解 例如,如果客户端订阅主题 “sport/tennis/player1/#”,它会收到使用下列主题名发布的消息:
“sport/tennis/player1”
“sport/tennis/player1/ranking”
“sport/tennis/player1/score/wimbledon”
非规范性注解
“sport/#”也匹配单独的 “sport” ,因为#包括它的父级。
“#”是有效通配符并会收到所有的应用消息。
“sport/tennis/#”也是有效的。
“sport/tennis#”是无效的。
“sport/tennis/#/ranking”是无效的。
4.7.1.3 单级通配符 Single level wildcard
Single level wildcard
加号 (‘+’ U+002B) 是仅能匹配一个主题级别的通配符。
==在主题过滤器的任意级别都可以使用单级通配符,包括第一个和最后一个级别。然而在使用的级别,它必须
占据过滤器的整个级别==[MQTT-4.7.1-3]。可以在主题过滤器中的多个级别中使用它,并可以可以和多级通配符一起使用。
非规范性注解 例如, “sport/tennis/+” 匹配 “sport/tennis/player1” 和 “sport/tennis/player2” ,但是不匹配 “sport/tennis/player1/ranking” 。同时,由于单级通配符只能匹配一个级别, “sport/+” 不匹配 “sport” 但是却匹配 “sport/”。 非规范性注解
“+” 有效通配符。
“+/tennis/#” 有效通配符。
“sport+” 无效通配符。
“sport/+/player1” 有效通配符。
“/finance” 匹配 “+/+” 和 “/+” ,但是不匹配 “+”。
4.7.2 以$开头的主题 Topics beginning with $
Topics beginning with $
==服务端不能
将$字符开头的主题名匹配以通配符 (#或+) 开头的主题过滤器== [MQTT-4.7.2-1]。服务端应该阻止客户端使用这种主题名与其它客户端交换消息。服务端实现可以将$开头的主题名用作其他目的。
非规范性注解
$SYS/ 被广泛用作包含服务器特定信息或控制API的主题的前缀。
应用不能将$字符开头的主题用于自身。
非规范性注解
订阅 “#” 的客户端不会收到任何发布到以 “$” 开头主题的消息。
订阅 “+/monitor/Clients” 的客户端不会收到任何发布到 “$SYS/monitor/Clients” 的消息。
订阅 “$SYS/#” 的客户端会收到发布到以 “$SYS/” 开头主题的消息。
订阅 “$SYS/monitor/+” 的客户端会收到发布到 “$SYS/monitor/Clients” 主题的消息。
如果客户端想同时接受以 “$SYS/” 开头主题的消息和不以$开头主题的消息,它需要同时订阅 “#” 和 ““$SYS/#”。
4.7.3 主题语义和用法 Topic semantic and usage
Topic semantic and usage
主题名和主题过滤器必须符合下列规则:
==所有的主题名和主题过滤器都
必须
有一个字符长度== [MQTT-4.7.3-1]。主题名和主题过滤器是区分大小写的。
主题名和主题过滤器可以包含空格字符。
主题名或主题过滤器以前置或后置斜杠 “/” 区分。
只包含斜杠 “/” 的主题名或主题过滤器是合法的。
==主题名和主题过滤器
不能
包含空字符 (Unicode U+0000)== [Unicode] [MQTT-4.7.3-2]。==主题名和主题过滤器是UTF-8编码字符串,它们
不能
超过65535字节== [MQTT-4.7.3-3]。见 1.5.3节。
除了不能超过UTF-8编码字符串的长度限制之外,主题名或主题过滤器的级别数量没有其它限制。
==匹配订阅时,服务端不能
对主题名或主题过滤器执行任何规范化处理,也不能修改或替换任何未识别的字符== [MQTT-4.7.3-4]。主题过滤器中的每个非通配符级别需要逐字符匹配命中主题名中对应的级别才能匹配成功。
非规范性注解 使用UTF-8编码规则意味着,可以通过比较UTF-8编码字节或者解码后的Unicode字符来实现主题过滤器和主题名的比较. 非规范性注解
“ACCOUNTS” 和 “Accounts” 是不同的主题名。
“Accounts payable” 是有效的主题名
“/finance” 和 “finance” 是不同的。
应用消息会分发给匹配的客户端,匹配规则是,客户端订阅的主题过滤器与应用消息的主题名相匹配。主题资源可能是管理员在服务端预先定义好的,也可能是服务端收到第一个订阅或使用那个主题名的应用消息时动态创建的。 服务端可以
使用安全组件来对给定客户端的主题资源进行选择性授权操作.
4.8 错误处理 Handling errors
Handling errors
==除非另有说明,如果服务端或客户端遇到了协议违规的行为,必须
关闭传输导致协议违规的控制报文的网络连接== [MQTT-4.8.0-1]。
客户端或服务端可能会遇到瞬态错误(例如内部缓冲区满态)导致无法成功处理MQTT报文。
==如果客户端或服务端处理入站控制报文时遇到了瞬态错误,就必须
关闭传输那个控制报文的网络连接== [MQTT-4.8.0-2]。==如果服务端发现了瞬态错误,它不应该
断开连接或者执行任何对其它客户端有影响的操作==。
Last updated