正文
- 前提
- MQTT结构
- 可变报文头(Variable Header)
- 有效负荷(payload)
- 固定报文头(Fixed Header)
- 消息类型(Message Type)
- QoS级别标志(0,1,2)
- Dup、Retain
- Remaining Length
前提
这里主要讲一下MQTT的结构,另外结合netty来说下具体参数的设置问题。
MQTT结构
首先基本概念,结构包含三个部分,分别为:固定报文头(Fixed Header)、可变报文头(Variable Header)、有效负荷(payload)。
通俗的介绍下这三个部分:
可变报文头(Variable Header)
可有可无
主要包含协议名,协议版本,连接标志,心跳间隔时间,连接返回码,主题名、是否有遗嘱、是否有用户名密码等等,这个自己定义,其中协议版本号一定要写对,否则在netty中使用会报错的,另外就是主题名了,这就相当于mq中的路由键一样,根据需求来写。
有效负荷(payload)
可有可无
这个就是你实际要发送的消息内容了。
固定报文头(Fixed Header)
一定要有
很好理解,就是固定不变的几个字段,包括:消息类型(Message Type)、QoS级别标志(0,1,2)、Dup、Retain、Remaining Length。
消息类型(Message Type)
这个就不多说了参考 协议类型
在netty中表现:
QoS级别标志(0,1,2)
这个就是消息服务质量等级了,有三个级别,级别越高,消息越精准。
Qos 0:最多分发一次,消息的传递完全依赖底层的TCP/IP网络,协议里没有定义应答和重试。消息只会到达服务端一次,要么就没到达。
Qos 1:至少分发一次、服务器的消息接收由PUBACK消息进行确认,如果通信链路或设备异常,或指定时间内没有收到确认消息,发送端会重发这条在消息头中设置了Dup位的消息。
Qos 2:只分发一次。最高级别的消息传递,消息丢失和重复都是不可接受的,使用这个服务质量等级会有额外的开销。
Dup、Retain
-
Dup 就是一个标志,0或false、1或true,在qos大于0的情况下还需要设置MessageId。
默认为0,只占用一个字节,表示第一次发送,如果设置为1,表示当前消息先前已经被传送过,需要在下面的变长头部里多加MessageId,并需要回复确认,保证消息传输完成,但不能用于检测消息重复发送。
简单理解就是,假如A给B发送很多条消息,B收到之后要告诉A我收到了某一条消息,那么区分消息是哪一条,就需要用到唯一的MessageId,同时确认的时候将Dup设置为1发送回去即可。 -
Retain 代表是否需要缓存消息。
1:表示发送的消息需要一直持久保存(不受服务器重启影响),不但要发送给当前的订阅者,并且以后新来的订阅了此Topic name的订阅者会马上得到推送。
0:仅仅为当前订阅者推送此消息。
假如服务器收到一个空消息体(zero-length payload)、RETAIN = 1、已存在Topic name的PUBLISH消息,服务器可以删除掉对应的已被持久化的PUBLISH消息。简单说就是:消息是否要存储,同时是否需要发送给新订阅的客户端。
Remaining Length
这个是剩余长度。
剩余长度=可变报头长度+payload长度。
可变报头长度=主题名长度+标识符长度(固定为 2)。
payload长度=实际消息内容的字节长度。
举个例子:发送一个字符串消息“1234”并且主题名为“test”,那么剩余长度应该就等于4+4+2=10.
对于netty来说,直接将对象转成json字符串,然后转成byte数组获取长度,当然在使用netty的时候,我们可以直接把这个值设置为0
,然后netty提供的mqtt的编码器会自动为我们计算这个剩余长度并且赋值,很方便,测试过,很准确。
当然如果我们没用netty,使用原生的MQTT,那么这个长度的计算和赋值方法就需要我们自己来算了。
那么请参考这里:MQTT协议-CONNECT报文剩余长度计算
简单来说,这就是人为设置的表示长度的规则,
先说个概念,再去看上边的文章,更好理解,剩余长度最多占用四个字节,每个字节有八位bit,这八位放的是二进制数,其中八位中前七位表示实际的数,最后一位代表是否还有值
,这么说吧,假如一个字节全部取最大值1,那么前七位都是1的二进制是多少呢?
127,但如果实际长度是128怎么办,那么一个字节就没办法表示了,那就把最后一位(前七位代表实际数字)改成1,然后再增加一个字节来表示,以此类推,如果第二个字节还无法表示这个数,那就继续往下,但是最多四个字节。