需求:
当mqtt服务器或客户端发生网络问题,导致客户端不可用,出现了生产故障,导致设备离线,引发一系列的问题。为了解决这个问题,我们需求对mqtt客户端进行重连配置,对mqtt服务器进行故障检测,重启配置,实现程序的健壮性。
1.引入pom依赖
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.1</version>
</dependency>
2.V1版本,通过设置(AutomaticReconnect) 进行断线重连,当服务端或客户端服务器网络故障(不可用),mqtt客户端不会进行重试连接
class TestV1{
private MqttClient client = null;
private void initMq() {
String serverUri = "tcp://localhost:1883";
String clientId = "MQTT-CLIENT";
try {
client = new MqttClient(serverUri, clientId, new MemoryPersistence());
} catch (MqttException e) {
return;
}
//客户端连接参数
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName("test");
options.setPassword("test".toCharArray());
options.setConnectionTimeout(30);
options.setKeepAliveInterval(60);
//设置自动重连
options.setAutomaticReconnect(true);
//设置回调
client.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {
// no need rec
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
if (!token.isComplete()) {
}
}
@Override
public void messageArrived(String topic, MqttMessage message) {
}
});
try {
client.connect(options);
subscribe();
} catch (MqttException e) {
return;
}
}
private void subscribe(){
try {
//订阅队列
client.subscribe("test_topic", 2, (topic, message) -> {
String msg = new String(message.getPayload(), StandardCharsets.UTF_8);
});
} catch (MqttException e) {
return;
}
}
}
3.V2 版本,主动断开客户端(服务端)导致不可用,则会进行重试
class TestV2{
private MqttClient client = null;
private void initMq() {
String serverUri = "tcp://localhost:1883";
String clientId = "MQTT-CLIENT";
try {
client = new MqttClient(serverUri, clientId, new MemoryPersistence());
} catch (MqttException e) {
return;
}
//客户端连接参数
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName("test");
options.setPassword("test".toCharArray());
options.setConnectionTimeout(30);
options.setKeepAliveInterval(60);
//设置自动重连
options.setAutomaticReconnect(true);
//设置回调
client.setCallback(new MqttCallbackExtended() {
//连接成功回调,需要重新订阅主题
@Override
public void connectComplete(boolean reconnect, String serverURI) {
sendNotify(true);
subscribe();
}
//连接异常,进行重连
@Override
public void connectionLost(Throwable cause) {
retryConnection(3);
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
if (!token.isComplete()) {
}
}
@Override
public void messageArrived(String topic, MqttMessage message) {
}
});
try {
client.connect(options);
subscribe();
} catch (MqttException e) {
return;
}
}
private void subscribe(){
try {
//订阅队列
client.subscribe("test_topic", 2, (topic, message) -> {
String msg = new String(message.getPayload(), StandardCharsets.UTF_8);
//处理消息
});
} catch (MqttException e) {
return;
}
}
private void retryConnection(int retryNumber){
//当重试多次,依旧失败,就是机器故障,需要通知人工处理
if(retryNumber< 0){
sendNotify(false);
return;
}
try {
client.reconnect();
TimeUnit.SECONDS.sleep(30);
if(!client.isConnected()){
retryConnection(--retryNumber);
}
} catch (MqttException e) {
e.printStackTrace();
}catch (InterruptedException e){
e.printStackTrace();
}
}
private void sendNotify(boolean isSuccess){
//发送重试通知
}
}
4.说明
MqttCallbackExtended是MqttCallback增强,增加了连接成功的回调 。
以上是通过实际生产中实践得出的经验。想要了解更多的细节可以查看源码实现。
如有理解不当的地方,欢迎大家指出。