首页 > mosquitto, MQTT, TCP/IP > MQTT消息推送协议应用数据包超时是否需要重发?

MQTT消息推送协议应用数据包超时是否需要重发?

2013年11月3日 发表评论 阅读评论 15997次阅读    

今天在看MQTT协议文档,到处关于QoS(Quality of Service)的介绍,文档说如果没有收到对方的PUBREL等确认包,超时后server需要'delivery retry", 一开始觉得理所当然的,重发嘛,丢包,正常。

然后就看到消息重发(Message delivery retry)这一章:

4.2. Message delivery retry

Although TCP normally guarantees delivery of packets, there are certain scenarios where an MQTT message may not be received. In the case of MQTT messages that expect a response (QoS >0 PUBLISH, PUBREL, SUBSCRIBE, UNSUBSCRIBE), if the response is not received within a certain time period, the sender may retry delivery. The sender should set the DUP flag on the message.

上面说TCP在某种情景下下可能会丢包,一想不对呀,TCP能够保证可靠传输的,当然send()不保证对方能收到,但是至少是“尽量能保证”对方能收到。而且是:要么对方应用程序全部收不到,要么就是按序收到数据的。

比如发出去了A包,但是A.ack回包没有收到,超时了。这个时候协议说,server需要"the sender may retry delivery",也就是重传一个A‘ 的第二个包。

不应呀,于是问了问朋友,对方也觉得不应该的,虽然说TCP也不是可靠传输,不一定能保证对方能收到。但它无论如何能够保证对方要么前面后面的都收不到,要么前面的肯定在后面的之前收到。所以这么说来,是不需要重传的。没有必要。

可能协议没有说清楚,也许指的是说客户端挂了,bug了,把消息在对方代码里面丢了,core了什么的。所以查了查邮件列表什么的。找到了一个今年8月份的讨论,总算找到了原因,是文档没有写清楚,目前最新文档时3.1版本,邮件组里面说3.1.1版本已经修改了描述,但还没有发出来。

真正的重发只需要存在于连接出问题断开的情况,比如客户端重连了,而且上次断开之前没有叫我clean session,那server需要重发上次的数据,其实就等于是要补发离线记录一个道理。另外如果有老版本的TCP协议客户端存在,其不支持可靠传输,也需要重发。具体可以看这里的总结,大概的结论是:

1.只要连接没有断开,不需要重传;

2.协议这么写是为了兼容老版的TCP/IP协议,可能那些协议可能有丢包(到达应用层的丢包,不指IP层);

3. 在3.1.1版已修改了表述。

Share
分类: mosquitto, MQTT, TCP/IP 标签: ,
  1. 向往
    2019年5月30日15:33 | #1

    TCP的可靠传输指的是传输层的可靠传输,在MQTT应用层,应该还是需要做重传的。传输层的不丢帧不代表上层的不丢包。比如说传输到一半,TCP断掉重连了,对于TCP层来说传输完的那一半还是可靠地。但对于整个数据包来说不完整了,这时的ack超时肯定是要重传的。

    我感觉MQTT3.1.1中这段话有问题。
    以上是我的理解。最近我也在实现MQTT协议,希望可以和您交流一下。 微信号:xiangwangcheng

  2. 2016年12月5日18:14 | #2

    云巴是基于MQTT协议、采用Erlang/OTP架构设计的实时通信系统。我们在产品中也定义了QoS的相关设置。

    QoS,全称为 Quality of Service,即服务质量。在 MQTT 协议中,QoS 可分为以下三个等级:
    “QoS = 0”: At most once. Fire and Forget. (至多一次,发完即删,不保证送达。)
    “QoS = 1”: At least once. Acknowledged delivery. (保证至少送达一次。)
    “QoS = 2”: Exactly once. Assured delivery. (保证送达,且仅送达一次。)

    QoS 为 0 时,消息发送后,无论服务端有没有收到这条消息,都不会重发,也不会等任何回应。 这种即发即删的传输方式无疑是最高效的,网络通信的压力也比较小。

    QoS 为 1 时,服务器收到消息后会回应一个 PUBACK。 如果发送方或者通信链路出了问题,或是在既定的时间内没收到 PUBACK 的话, 发送方会把 DUP 置位,并重发消息。服务器收到重发来的消息,会重新发布给订阅者,并再次回复 PUBACK 给发送方。 因而消息至少送达一次。 在 MQTT 协议中,SUBSCRIBE 和 UNSUBSCRIBE 消息的 QoS 都为 1 级。
    QoS 为 1 时,消息会带 Message ID。

    QoS 2 级是 QoS 1 级的升级版,也是消息传输的最高等级。 它不仅能保证消息送达,且保证只送达一次。
    与 QoS 1 级一样,QoS 2 级的消息也带有 Message ID。

    如果传输过程中检测到错误,或者既定时间内没收到期待的回应,则会从没收到确认消息的出错处开始尝试重发。 即,重发 PUBLISH 或重发 PUBREL。

    具体可以查看我们的文档:https://yunba.io/docs/product_kb_qos

  1. 2013年11月4日02:03 | #1

注意: 评论者允许使用'@user空格'的方式将自己的评论通知另外评论者。例如, ABC是本文的评论者之一,则使用'@ABC '(不包括单引号)将会自动将您的评论发送给ABC。使用'@all ',将会将评论发送给之前所有其它评论者。请务必注意user必须和评论者名相匹配(大小写一致)。