mqtt协议笔记之发布流程 -凯发k8网页登录

记录工作/学习的点点滴滴。

前言

这次要讲到客户端/服务器的发布消息行为,与publish相关的消息类型,会在这里看到。

publish

客户端发布消息经由服务器分发到所有对应的订阅者那里。一个订阅者可以订阅若干个主题(topic name),但一个publish消息只能拥有一个主题。

消息架构一览:

 description76543210
fixed header/固定头部
byte 1   message type(3) dup flag qos level retain
    0 0 1 1 0 0 1 0
byte 2 remaining length
variable header/可变头部
topic name
byte 1 length msb (0) 0 0 0 0 0 0 0 0
byte 2 length lsb (3) 0 0 0 0 0 0 1 1
byte 3 'a' (0x61) 0 1 1 0 0 0 0 1
byte 4 '/' (0x2f) 0 0 1 0 1 1 1 1
byte 5 'b' (0x62) 0 1 1 0 0 0 1 0
message identifier
byte 6 message id msb (0) 0 0 0 0 0 0 0 0
byte 7 message id lsb (10) 0 0 0 0 1 0 1 0
playload/消息体
blob,二进制对象形式。二进制具体包含的内容和格式,可有应用程序自身定义。若消息体为空(0长度)也是可能的。

固定头部

dup flag,设为0,表示当前为第一次发送。

retain flag,只有在publish消息中才有效。

  • 1:表示发送的消息需要一直持久保存,不但要发送给当前的订阅者,并且以后新来的订阅了此topic name的订阅者会马上得到推送。 备注:新来乍到的订阅者,只会取出最新的一个retain flag = 1的消息推送,不是所有。
  • 0:仅仅为当前订阅者推送此消息。

可变头部

topic name,utf-8编码字符串形式,不支持通配符!

消息体

一般作为utf-8编码写入接口,但不排除自定义的消息格式。

空的消息体(zero-length)的publish消息也可以是合法的。

当服务器接收到空消息体(zero-length payload)、retain = 1、具有topic name的一个publish特殊消息,表示同时满足retain = 1、相同topic name的这两个特征的被持久化publish消息,可被删除。

response/响应

固定头部qos level决定了消息中间件针对发布者具体需要响应的内容:

qos level expected response
qos 0 none
qos 1 puback
qos 2 pubrec

备注:仅仅针对发布publish消息的发布者。

actions:

无论是订阅者还是服务器接收到publish消息之后,需要根据qos level执行不同动作。

qos level expected action
qos 0 发送到所有感兴趣者
qos 1 持久化记录下来,发送到所有感兴趣的参与者,返回一个puback消息给发送者
qos 2 持久化记录下来,暂时不发送所有感兴趣的参与者,返回一个pubrec消息给发送者

如果服务器收到publish消息,参与者指的是订阅者。如果订阅者收到publish消息,参与者就是服务器。 需要注意:

  1. 发布者发布的publish消息发送到服务器,在payload/消息体处可能夹带有私货,可能含有自定义的数据 格式
  2. 若兼容mqtt客户端,经由服务器分发到所有对应订阅者处只能是规规矩矩的publish消息,并且固定头部的retain标志不能被设置成有效值1

授权

未经授权的发布者提交的publish消息,服务器会忽略掉,客户端不会被通知。

puback

作为订阅者/服务器接收(qos level = 1)publish消息之后对发送者的响应,整个消息不复杂。

 description76543210
fixed header/固定头部
byte 1   message type (4) dup flag qos flags retain
    0 1 0 0 x x x x
byte 2   remaining length (2)
    0 0 0 0 0 0 1 0
variable header/可变头部
message identifier
byte 1 message id msb (0) 0 0 0 0 0 0 0 0
byte 2 message id lsb (10) 0 0 0 0 1 0 1 0

虽没有消息体,但可变头部附加一个16位的无符号short类型。

pubrec

字面意思为assured publish received,作为订阅者/服务器对qos level = 2的发布publish消息的发送方的响应,确认已经收到,为qos level = 2消息流的第二个消息。 和puback相比,除了消息类型不同外,其它都是一样。

 description76543210
fixed header/固定头部
byte 1   message type (5) dup flag qos flags retain
    0 1 0 1 x x x x
byte 2   remaining length (2)
    0 0 0 0 0 0 1 0
variable header/可变头部
message identifier
byte 1 message id msb (0) 0 0 0 0 0 0 0 0
byte 2 message id lsb (10) 0 0 0 0 1 0 1 0

无论是订阅者还是服务器,在消费pubrec消息之后需要发送一个pubrel消息给发送者(和pubrec具有同样的消息id),确认已收到。

pubrel

qos level = 2的协议流的第三个消息,有publish消息的发布者发送,参与方接收。完整示范如下:

 description76543210
fixed header/固定头部
byte 1   message type (6) dup flag qos flags retain
    0 1 1 0 0 0 1 x
byte 2   remaining length (2)
    0 0 0 0 0 0 1 0
variable header/可变头部
message identifier
byte 1 message id msb (0) 0 0 0 0 0 0 0 0
byte 2 message id lsb (10) 0 0 0 0 1 0 1 0

qos level 1,pubrel消息要求如此。

dup flag 为0,表示消息第一次被发送。

毫无疑问,剩余长度为2个byte长度。

可变头部中,消息id和发布者接收到的pubrec所包含的消息id是一致的。

动作:

  1. 服务器接收到发布者(a)的pubrel消息,此时服务器让发布者(a)刚才发布publish消息可用,发送此publish消息给所有订阅此主题的订阅者,然后发送pubcomp消息给发布者(a)
  2. 可变头部包含消息id和服务器接收的pubrel消息id是一致的。 一个订阅者接收到pubrel消息,订阅者使publish消息可用,然后反馈一个pubcomp消息给服务器

pubcomp

作为qos level = 2消息流第四个,也是最后一个消息,由收到pubrel的一方向另一方做出的响应消息。

完整的消息一览,和pubrel一致,除了消息类型。

 description76543210
fixed header/固定头部
byte 1   message type (7) dup flag qos flags retain
    0 1 1 1 x x x x
byte 2   remaining length (2)
    0 0 0 0 0 0 1 0
variable header/可变头部
message identifier
byte 1 message id msb (0) 0 0 0 0 0 0 0 0
byte 2 message id lsb (10) 0 0 0 0 1 0 1 0

当客户端接收一个pubcomp消息时,客户端摒弃原来的消息,因为它已经成功发送消息到服务器。

小结

消息的发布和确认等一些流程,主要是跟消息发布者所设定的qos level有关;稍加整理,绘制了下面一张图,理解起来可能会更清晰些:

上图针对的是客户端发布消息到服务器端的方向。

为了确保消息已经成功传递过去,只有收到了确认,才会让人特别放心。

在qos level = 2时,通信双方都需要知道各自的确认流程以及所处阶段等,交互很多,数据量大的情况下,可能会造成数据线路传递拥塞。服务器选择qos = 0/1,大部分情况都是可以应对的。 比如重要消息,就要确保对方都要收到,然后彼此确认,ok,这个消息是真实、有效的。

无论qos level为0、1,还是2,服务器(具备所有条件都满足之后)总要把收到的具体内容和topic组装成一个新的publish message(也不一定要重新构造,但要求推送的publish消息,一定要具有明确的主题和内容,retain标志不能设置为1)推送到所有感兴趣的订阅者。

嗯,消息的发布来源别忘记还有可能来自connect消息中的will topic和will message,若是设置了will flag标记的话。

posted on 2014-02-10 23:42 nieyong 阅读(17066) 评论(5)     所属分类: mqtt

# re: mqtt协议笔记之发布流程 2014-02-11 08:14

期待博主更新文章。。。加油
  回复     

# re: mqtt协议笔记之发布流程[未登录] 2015-10-26 16:56

请问,在服务器端,用代理转发的方式。是一个sub订阅多个订阅号(多个设备的id)->myaql 方式合理;还是实现多线程sub,每一个线程的sub订阅一个id在同步到mysql的方式合理。  回复     

# re: mqtt协议笔记之发布流程 2016-12-27 09:00

博主牛人呀,有一个qos2的问题请教,为什么qos2需要4次包,2次不就可以了吗?还望回复。  回复     

# re: mqtt协议笔记之发布流程 2017-01-05 15:20 nieyong

@haven

兄弟,针对qos2,为了便于说明,我们先假设一个方向,server -> client:

----publish--->
<----pubrec----
----pubrel---->
<----pubcomp---

1. server发送publish消息到client,client接收之后需要确认收到嘛,就返回pubrec吧;但此时client仅仅是把数据发送出去了而已,至于server端收不收到那就不得而知
2. server接收clientpubrec消息之后,需要回一个pubrel消息告诉client自己收到啦,同样道理也仅仅只是发送出去,client是不是能收到的这个响应,心里面也没谱呀
3. client收到来自server的pubrel之后,就非常明白自己针对publish消息做出的pubrec响应消息在server端是已经收到啦,但是需要告诉server,自己收到它的再三确认啦
4. server端此时等待client上报pubcomp消息,一旦接收到之后,表示针对某个消息双方都再三确认了,这事就没有问题啦

其核心所设定网络是不靠谱的,任何一次发送数据到对端,都有可能因收不到(比如发送之后,某一端断网啦,或中间路由设备因为容量满了抛弃啦)。

好比双发约定一件事:

server - 我给你说说这件事....
client - 我同意了你这样做。
server - 你确定你同意了?
client - 是的,我同意了。
server - ok,那这事就这么定了,我知道该怎么做啦。  回复     

# re: mqtt协议笔记之发布流程 2017-01-10 13:03

@nieyong
谢谢兄弟的回复,

其实我还是觉得两次就可以搞定了。同样以server -> client为例

1. server发送publish消息到client,client接收之后需要确认收到嘛,就返回pubrec吧;但此时client仅仅是把数据发送出去了而已,至于server端收不收到那就不得而知.
2. server可能收到了pubrec,也可能没有收到
a. server收到了pubrec, 这时候就表示client收到消息了,表示成功递送消息了。
b. server没有收到pubrec,等待一定时间后,重发publish即可。

在1中,client收到publish后就把数据保存在数据库中,如果收到重复publish重数据库就可以知道是重复数据。
在2中,超时就重传publish即可。
感觉这样两步完全满足qos2了呀!!


其实我在设计一套私有im协议,用于自己的app中,希望能加你qq探讨一下mqtt的qos2问题。
我的qq:357545146  回复     


只有注册用户后才能发表评论。


网站导航:
              
 

公告

所有文章皆为原创,若转载请标明出处,谢谢~

新浪微博,欢迎关注:

导航

2017年1月
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234

统计

常用链接

留言簿(58)

随笔分类(129)

随笔档案(149)

个人收藏

最新随笔

搜索

最新评论

阅读排行榜

评论排行榜

网站地图