目标
理解客户端在断开连接后的CONNECT重连协议
准备
参见 “MQTT 实践” ,“MQTT-Java 连接协议” 完成测试工程配置
实验场景步骤
- 客户端连接服务端
- 客户端订阅主题
- 客户端断开连接
- 客户端停留10秒
- 客户端重连服务端
- 通过MQTTX 发布一个主题为"harvey",内容为“连接成功了”的信息
- 客户端收到主题为“harvey”的"连接成功了"消息
实验代码
/**
*
* 客户端连接 & 订阅主题 & 客户端断开 & 重新连接
*
*/
private static void subscribeAndDisconnectAndReConnect(){
MemoryPersistence persistence = new MemoryPersistence();
try {
MqttConnectionOptions connOpts = new MqttConnectionOptions();
connOpts.setCleanStart(false);
connOpts.setKeepAliveInterval(0);
connOpts.setSessionExpiryInterval(60L);
MqttAsyncClient sampleClient = new MqttAsyncClient(MQTTConfigue.broker, MQTTConfigue.clientId, persistence);
IMqttToken token = sampleClient.connect(connOpts);
token.waitForCompletion();
subscription(sampleClient);
IMqttToken iMqttToken = sampleClient.disconnect();
iMqttToken.waitForCompletion();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
sampleClient.reconnect();
} catch (MqttException e) {
HarveyDebug.d(e.getMessage());
}
} catch(MqttException me) {
System.out.println("reason "+me.getReasonCode());
System.out.println("msg "+me.getMessage());
System.out.println("loc "+me.getLocalizedMessage());
System.out.println("cause "+me.getCause());
System.out.println("excep "+me);
me.printStackTrace();
}
}
客户端连接MQTT服务器日志
2023-08-29 15:51:28:206 Send 包类型:CONNECT
2023-08-29 15:51:28:208 Send Message Header(二进制内容) : 00010000 00100111 00000000 00000100 01001101 01010001 01010100 01010100 00000101 00000000 00000000 00000000 00000101 00010001 00000000 00000000 00000000 00111100
2023-08-29 15:51:28:208 Send Message Header(字符串内容) : '�MQTT������<
2023-08-29 15:51:28:209 Send Message payload(二进制内容) : 00000000 00010101 01001001 01101110 01110100 01100101 01001001 01001001 01101001 01001010 00100000 01001001 01000100 01000101 01000001 00100000 01000011 01101100 01101001 01100101 01101110 01110100 00100000
2023-08-29 15:51:28:209 Send Message payload(字符串内容) : 内容长度=23,内容=�InteIIiJ IDEA Client
2023-08-29 15:51:28:211 Receive 包类型:CONNACK
2023-08-29 15:51:28:213 Receive Message Header(二进制内容) : 00100000 00001100 00000000 00000000 00001001 00010011 11111111 11111111 00100001 00000000 00010100 00100010 00000000 00001010
2023-08-29 15:51:28:213 Receive Message Header(字符串内容) : �� ��!�"�
2023-08-29 15:51:28:213 Receive Message payload(二进制内容) :
2023-08-29 15:51:28:214 Receive Message payload(字符串内容) :
2023-08-29 15:51:28:220 Send 包类型:SUBSCRIBE
2023-08-29 15:51:28:220 Send Message Header(二进制内容) : 10000010 00001100 00000000 00000001 00000000
2023-08-29 15:51:28:220 Send Message Header(字符串内容) : ���
2023-08-29 15:51:28:221 Send Message payload(二进制内容) : 00000000 00000110 01101000 01100001 01110010 01110110 01100101 01111001 00000001
2023-08-29 15:51:28:221 Send Message payload(字符串内容) : 内容长度=9,内容=�harvey
2023-08-29 15:51:28:221 Receive 包类型:SUBACK
2023-08-29 15:51:28:222 Receive Message Header(二进制内容) : 10010000 00000100 00000000 00000001 00000000
2023-08-29 15:51:28:222 Receive Message Header(字符串内容) : ���
2023-08-29 15:51:28:223 Receive Message payload(二进制内容) : 00000001
2023-08-29 15:51:28:223 Receive Message payload(字符串内容) :
2023-08-29 15:51:28:224 Send 包类型:DISCONNECT
2023-08-29 15:51:28:224 Send Message Header(二进制内容) : 11100000 00000010 00000000 00000000
2023-08-29 15:51:28:224 Send Message Header(字符串内容) : ���
2023-08-29 15:51:28:225 Send Message payload(二进制内容) :
2023-08-29 15:51:28:225 Send Message payload(字符串内容) : 内容长度=0,内容=
2023-08-29 15:51:38:336 start connect remote server : 127.0.0.1:1883
2023-08-29 15:51:38:652 Send 包类型:CONNECT
2023-08-29 15:51:38:652 Send Message Header(二进制内容) : 00010000 00100111 00000000 00000100 01001101 01010001 01010100 01010100 00000101 00000000 00000000 00000000 00000101 00010001 00000000 00000000 00000000 00111100
2023-08-29 15:51:38:652 Send Message Header(字符串内容) : '�MQTT������<
2023-08-29 15:51:38:653 Send Message payload(二进制内容) : 00000000 00010101 01001001 01101110 01110100 01100101 01001001 01001001 01101001 01001010 00100000 01001001 01000100 01000101 01000001 00100000 01000011 01101100 01101001 01100101 01101110 01110100 00100000
2023-08-29 15:51:38:654 Send Message payload(字符串内容) : 内容长度=23,内容=�InteIIiJ IDEA Client
2023-08-29 15:51:38:655 Receive 包类型:CONNACK
2023-08-29 15:51:38:655 Receive Message Header(二进制内容) : 00100000 00001100 00000001 00000000 00001001 00010011 11111111 11111111 00100001 00000000 00010100 00100010 00000000 00001010
2023-08-29 15:51:38:656 Receive Message Header(字符串内容) : � ��!�"�
2023-08-29 15:51:38:656 Receive Message payload(二进制内容) :
2023-08-29 15:51:38:656 Receive Message payload(字符串内容) :
2023-08-29 16:00:52:193 Receive 包类型:PUBLISH
2023-08-29 16:00:52:197 Receive Message Header(二进制内容) : 00110010 00011010 00000000 00000110 01101000 01100001 01110010 01110110 01100101 01111001 00000000 00000001 00000000
2023-08-29 16:00:52:198 Receive Message Header(字符串内容) : 2�harvey��
2023-08-29 16:00:52:198 Receive Message payload(二进制内容) : 11101000 10111111 10011110 11100110 10001110 10100101 11100110 10001000 10010000 11100101 10001010 10011111 11100100 10111010 10000110
2023-08-29 16:00:52:199 Receive Message payload(字符串内容) : 连接成功了
2023-08-29 16:00:52:216 Send 包类型:PUBACK
2023-08-29 16:00:52:216 Send Message Header(二进制内容) : 01000000 00000010 00000000 00000001
2023-08-29 16:00:52:217 Send Message Header(字符串内容) : @�
2023-08-29 16:00:52:217 Send Message payload(二进制内容) :
2023-08-29 16:00:52:217 Send Message payload(字符串内容) : 内容长度=0,内容=
MQTT 协议规范对照解析
MQTT 协议结构
整体结构 :固定头+可变头+内容
协议发生流程
| 第一步 | 第二步 | 第三步 | 第四步 | 第五步 | 第六步 | 第七步 | 第八步 |
|---|---|---|---|---|---|---|---|
| CONNECT | CONNACK | SUBSCRIBE | SUBACK | CONNACK | CONNACK | PUBLISH | PUBACK |
| 连接 | 连接ACK | 订阅 | 订阅ACK | 连接 | 连接ACK | 接收发布主题 | 回复发布主题ACK |
CONNECT协议详细解析
连接协议Header对比
通过对比,发现客户端在使用reconnect()方法重新连接时,固定请求头没有区别
| 场景 | 固定头类型 | 剩余长度 | 协议名 | 协议版本号 | 连接标识位 | 连接保活时间 | 属性长度 | 属性:session有效期 | session有效期值 |
|---|---|---|---|---|---|---|---|---|---|
| 第一步Header | 00010000 | 00100111 | 00000000 00000100 01001101 01010001 01010100 01010100 | 00000101 | 00000000 | 00000000 00000000 | 00000101 | 00010001 | 00000000 00000000 00000000 00111100 |
| 第五步Header | 00010000 | 00100111 | 00000000 00000100 01001101 01010001 01010100 01010100 | 00000101 | 00000000 | 00000000 00000000 | 00000101 | 00010001 | 00000000 00000000 00000000 00111100 |