在MQTT中,消息传递模式是采用发布订阅模式(Publish-Subscribe Pattern),它将发送消息的客户端(发布者)与接收消息的客户端(订阅者)解耦,使得两者不需要建立直接的联系也不需要知道对方的存在。看这两图
发布者(Publisher)
负责将消息发布到主题上,发布者一次只能向一个主题发送数据,发布者发布消息时也无需关心订阅者是否在线。
订阅者(Subscriber)
订阅者通过订阅主题接收消息,且可一次订阅多个主题。MQTT还支持通过共享订阅的方式在多个订阅者之间实现订阅的负载均衡。
比如一个网站有社会新闻、体育讲坛等频道,那么客户端只要找到自己感兴趣的进行订阅就可以了。一个客户端可以向服务器订阅多个主题。而所谓的发布就是客户端对不同的主题进行发布信息。 这个时候只要订阅这个主题的客户端就可以接收到来自服务端的新闻。我们的手机常常会接收到一些推送的信息。事实上有很多App应用都是用MQTT协议来进行的。所以不难看出服务端主要是负责客户端和客户端的之间信息的传输和信息管理,如图所示:
注意:发布者也是客户端,订阅者也是客户端,发布也好,订阅也好就有【主题】这个概念
什么是主题(Topic?)?
在 MQTT 中,主题一词是指代理用于为每个连接的客户端过滤消息的 UTF-8 字符串。主题由一个或多个主题级别组成。每个主题级别由正斜杠(主题级别分隔符)分隔。
主题是用于标识和分类消息的字符串
例如,sensors/temperature
是一个主题,用于表示温度传感器的数据。
主题的结构可以根据实际需求进行设计,但通常遵循以下几个原则:
sensors/temperature/room1
表示位于"room1"的温度传感器数据。主题在MQTT中充当发布和订阅消息的关键标识符,它使得消息可以被准确地路由和传递给相应的订阅者。
第1个字节报文类型,固定值为8,从上面的14种报文类型看到是固定的8.
注意一个问题,为什么是82,我来给你讲透彻,估计很多人搞不懂这里为什么是16进制的82,明明是表中所说的8?
查报文类型中得到确实是8,换成二进制就是1000,用一个字节来表示,就是00101000,前面的0010是高位,1000是低,但在MQTT是用大端表示的,即要将原来的高位变低位,原来的低位变高位,所以00101000就要变成10000010(1000高低,0010低位),换成10进制就是130,用16进制表示就是0x82。
第2个字节剩余字节长度,注意这是指剩余字节的长度,意思是指从它开始到最后一共有多少个字节,包括自己在内,这个长度因为后面的主题多少不同,所以是变化的,但它只占1个字节。?
可变报头只有一个消息ID。消息ID是从客端端开始分配的,官文名词叫:package identifier,用于区分标识的序号的。
必须按照”主题字符长度,主题字符内容,Qos“的顺序依次出现。因为主题可能有多个,所以所占字节长度肯定是变化的,不是固定的。
当服务端处理SUBSCRIBE报文的时候,都会生成一个SUBACK 报文来回应订阅者,他的内容也很简单。?
?第1个字节,返回是9,这是固定的
?第2个字节,返回的是剩余字节长度
对于SUBACK 报文的可变报头里面也只有一个消息ID,专业名称叫package identifier。而且跟SUBSCRIBE报文的消息ID是一样子的。
有效载何的内容存放是订阅主题的服务质量要求(Requested QoS),主题相关的服务质量要求(Requested QoS),如下
QOS 0:0x00?
QOS 1:0x01?
QOS2 :0x02
这就是订阅的两个报文,看上去有点糊涂,有人肯定会说,要搞这些干肾么,直接使用库实现不就得了吗,里面肾么鬼报文关我卵事,你错了,真错了,你可以不掌握,但是作为高手,封装自己的库的时候就必须弄清楚,比如作为本作者来说,如果搞不清楚的话,还怎么在这写洋洋成千上万的文字?
一回生,二回熟,三回精,四回飞。