前言
关于MQTT基础课程系列(HIVEMQ)的【译文】工作已结束,期间有一些术语实在难以翻译为可理解的中文技术用语。为了进一步理解MQTT特性,本篇文章将通过自定义解析PAYLOAD的方式,来解惑分析MQTT规范中特定术语。
目标
解析PAYLOAD内容
准备
- 参见 "MQTT 实践" ,"MQTT-Java 连接协议" 完成测试工程配置
- 代码仓库:github.com/harveyblack...
- 协议规范:docs.oasis-open.org/mqtt/mqtt/v...
了解PAYLOAD
描述
有些MQTT控制包含一个payload, 并把它作为控制包的最后一部分。在PUBLISH控制包中,payload就是一个应用消息
数据包整体结构
包含PAYLOAD的控制包
控制包名称 | 选项 | 描述 |
---|---|---|
CONNECT | 必须 | 连接代理服务器(broker) |
SUBSCRIBE | 必须 | 订阅主题 |
SUBACK | 必须 | 订阅ACK |
UNSUBSCRIBE | 必须 | 解除主题的订阅 |
UNSUBACK | 必须 | 解除主题的订阅ACK |
PUBLISH | 可选 | 发布主题 |
解码PAYLOAD
CONNECT 控制包
1. MQTT规范
'3.1.3 CONNECT Payload'
2. 数据结构
- Client Identifier : Will Properties : Will Topic : Will Payload : User Name : Password
- 数据类型
想了解MQTT的数据类型,可参见"MQTT-java 数据描述(Data representation)"
- ClientID : UTF-8 Encoded, 即:长度(2个字节)+ 编码内容
- Will Properties
- Property Length : Variable Byte
- Will Delay Interval: Four Byte Integer
- Payload Format Indicator: Byte
- Message Expiry Interval: Four Byte Integer
- Content Type : UTF-8 Encoded
- Response Topic : UTF-8 Encoded
- Correlation Data : Binary
- User Property : UTF-8 String Pair
- Will Topic : UTF-8 Encoded
- Will Payload : Binary
- User Name : UTF-8 Encoded
- Password : Binary
3. 解码流程
根据CONNECT payload的结构来讲,共分5大部分,除ClientID没有前置条件,剩余部分都需要根据控制包头中的CONNECT Flags标志来作为前置条件来进行解码。
4. 代码片段
实验代码入口文件ExampleParsePayLoad.java
详细解析过程参见代码库中的HarveyDebug.java
文件,方法名为:parsePayload()
ini
/**
* header : 固定头和可变头
**/
public static void parsePayload(byte [] header, byte [] payload){
...
//3.1.3.1 Client Identifier (ClientID)
int payloadIndex = 0;
int clientIdentifierLength = (payload[payloadIndex] << 8)&0xff00 | payload[payloadIndex+1];
byte [] clientIdentifierB = new byte[clientIdentifierLength];
for(int k = 0; k < clientIdentifierLength; k++){
clientIdentifierB[k] = payload[payloadIndex + k];
}
payloadIndex = payloadIndex + clientIdentifierLength;
String clientIdentifier = new String(clientIdentifierB, StandardCharsets.UTF_8);
d("Client Identifier: " + clientIdentifier);
...
}
SUBSCRIBE 控制包
1. MQTT规范
'3.8.3 SUBSCRIBE Payload'
2. 数据结构
- Topic Filter : Subscription Options
- 数据类型
- Topic Filter : UTF-8 Encoded
- Subscription Options : Byte
3. 解码流程
4. 代码片段
实验代码入口文件ExampleParsePayLoad.java
详细解析过程参见代码库中的HarveyDebug.java
文件,方法名为:parsePayload()
ini
/**
* header : 固定头和可变头
**/
public static void parsePayload(byte [] header, byte [] payload){
...
int payloadIndex = 0;
while (payloadIndex < payload.length) {
{
int willTopicLength = (payload[payloadIndex++] << 8) & 0xff00 | payload[payloadIndex++];
byte[] willTopicB = new byte[willTopicLength];
for (int k = 0; k < willTopicLength; k++) {
willTopicB[k] = payload[payloadIndex + k];
}
payloadIndex = payloadIndex + willTopicLength;
String contentType = new String(willTopicB, StandardCharsets.UTF_8);
d("Topic Filters: " + contentType);
}
//Reserved Retain Handling RAP NL QoS
String Reserved = ((payload[payloadIndex] & 0xc0) >> 6) + "";
String RetainHandling = ((payload[payloadIndex] & 0x30) >> 4) + "";
String RAP = ((payload[payloadIndex] & 0x8) >> 3) + "";
String NL = ((payload[payloadIndex] & 0x4) >> 2) + "";
String QoS = (payload[payloadIndex] & 0x3) + "";
d("Reserved:" + Reserved + " , " + "RetainHandling:" + RetainHandling + " , " + "RAP:" + RAP + " , " + "NL:" + NL + " , " + "QoS:" + QoS);
payloadIndex++;
}
...
}
SUBACK,UNSUBSCRIBE,UNSUBACK,PUBLISH 控制包
依据本篇文章前两个类型的分析过程和实验代码,可自行尝试解码一下控制包