任何MQTT客户端是否实际重用了数据包标识符?

时间:2016-08-29 16:22:58

标签: mqtt

某些MQTT控制数据包(http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/csprd02/mqtt-v3.1.1-csprd02.html#_Toc385349761)需要数据包标识符。它由标准定义为16位整数,由每个客户端生成。在收到确认包之后,客户端可以重用标识符。因此,该标准允许最多64k的飞行中消息。在实践中,我看过的客户似乎只是递增一个计数器,因此允许客户端发送总共64k条消息。当计数器溢出时,两个生锈的MQTT客户端库都会发生混乱。 (更新2016-09-07 :如果生锈客户端在发布模式下编译然后它们不会出现混乱,数据包标识符的值变为0 - 在正常情况下这将起作用,但是。 ..)

有没有人知道MQTT客户端允许超过64k的消息/客户端(即重新使用数据包标识符)?我想知道这是否是一般我需要注意的限制,或者它是否仅仅是一些客户端。我已经快速查看了一致性测试,并且还没有看到太多表明这已经过检查 - 我会继续寻找。

编辑:可能是某些客户端将此作为限制正在进行的消息数量的副作用。 更新2016-09-07 生锈客户通过假设它们可以包裹溢出并且永远不会遇到滞后消息(可能是一个好赌注,但不能保证,并且如果它发生了一个丑陋的结果)来做到这一点)

1 个答案:

答案 0 :(得分:0)

正如您所指出的那样,数据包标识符旨在作为临时值,该临时值必须持续到接收到并确认已发布的数据包为止。

确认后,您可以(或不可以)重复使用标识符。

大多数客户端都在嵌入式系统上运行,并且它们跟踪的数据包不超过单个数据包(因此仅处理单个标识符),因为它们在进行任何其他发布之前会等待ACK或REC / COMP。

因此对于这些客户端,即使是单个标识符也足够。 请注意,对于QoS 1,记住标识符是徒劳的,因为如果下一个数据包不是ACK,则重新发送该数据包是有效的(因此,在接收到的数据包中您具有要答复的标识符)。

对于确实支持交错发布数据包的稀有客户端,它们仅需要随时支持2个有效标识符(也就是说,如果他们已经收到QoS 2数据包,并用PUBREC应答,然后再接收另一个QoS 1或2包)。 一旦他们接收到PUBREL数据包,就可以用PUBCOMP进行答复而无需记住标识符(它位于PUBREL标头中),因此他们唯一需要记住的标识符是在PUBLISH和PUBREC数据包之间。如果它们允许交错的发布数据包,则唯一需要第二个标识符的情况是它们在发布时同时接收发布的数据包。

现在,从代理的角度来看,大多数实现都使用16位计数器每个客户端,因此从理论上讲,它们可以支持多达65535个传输中的数据包。

实际上,由于发布数据包的最小大小为8个字节(通常更多),这意味着每个潜在数据包必须至少存储9个字节(附加字节用于记住当前数据包)处于QoS 2)状态,因此在最小情况下只有一半MB的内存,但在现实生活中可能更多,因为您永远不会有空的发布有效负载和主题名称。

如您所见,嵌入式系统几乎不可能实现具有这种存储要求的功能,因此采取了捷径。

在大多数情况下,要么服务器不允许这么多未确认的数据包(通过简单地答复客户端以释放标识符),要么使用不同客户端之间的标识符池。

因此,通常,对于代理来说,最糟糕的情况只有在客户端不确认已发布的数据包时才会发生。如果经纪人没有从客户那里得到任何答案,它可以:

  • 关闭连接
  • 拒绝发送新发布的信息,或者
  • 忽略答案并重新发布

无论如何,所有这些策略都需要实施,因为您可能遇到一个问题,那就是客户端速度慢,发布商速度快和以及您的65535个标识符

由于您具有这些策略,因此无需为每个客户端浪费MB的内存,而可以更早地节省时间(同时保持合理的工作条件)。

最后,数据包标识符是处理最新数据包的识别的工具,而不是对所有收到的数据包进行 index 的工具。计数器足以应付这种情况,并且在考虑内存和带宽需求时,回绕不会造成任何问题。