問題
采用以下配置
connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
connOpts.setConnectionTimeout(10);
connOpts.setKeepAliveInterval(90);
connOpts.setAutomaticReconnect(true);
網絡斷開後,用戶端會進行重連,但是重連之前訂閱的主題就失效了,不再接受之前訂閱主題的消息。
解決方法
因為配置裡将cleanSession 設為 true ,當用戶端掉線時 ,伺服器端會清除 用戶端 session 。 重連後 用戶端會有一個新的session。
第一種
把配置裡的 cleanSession 設為false,用戶端掉線後 伺服器端不會清除session,當重連後可以接收之前訂閱主題的消息。當用戶端上線後會接受到它離線的這段時間的消息
但是這個隻是進行了重連,重連後還需要再次發起訂閱
對于離線消息為什麼不能接收到,我想說的是 你很有可能在再次連接配接的時候又重新訂閱了該topic。這樣是接收不到離線消息的。
離線消息是訂閱了某個topic的client 在斷開連接配接以後,在接下來又重新連接配接的時候,任然可以收到在它斷開連接配接的這段時間内,該topic上的消息。這就需要将client的 setCleanSession 設定為false,這樣伺服器才能保留它的session,再次建立連接配接的時候,它就會繼續使用這個session了。
注意:clientId 是不能更改的。
第二種
通過檢視 connect 方法的代碼發現
如果我們設定的 callback實作了 MqttCallbackExtended接口,就會把它設定給connectActionListener,我再來看看MqttCallbackExtended接口。
可以看到這個接口拓展了一個方法,該方法會在連接配接到伺服器成功時調用,正符合我們的要求。我隻需要實作這個接口并在這個方法裡從新訂閱之前的主題就行了。
這種方法重連之後不會收到離線期間該主題的消息
第三種:
//設定斷開後重新連接配接
options.setAutomaticReconnect(true);
但這樣重連是實作了,但是之前訂閱的主題卻接收不到消息了,需要重新訂閱主題才能正常接收消息,那我這個重新訂閱的代碼要怎麼再放進去呢,反正不是再connectionLost裡就是了,那是後連接配接還沒有重連連上!
繼續看MQTT的connec的源碼發現了一段代碼使我找到了解決方案
MqttReconnectCallback 是實作MqttCallbackExtended接口的
發現comms中有設定重連的回調對象,但是怎麼把這個回調由我們來主動放進去呢?繼續往下看源碼可以發現
也就是如果我們在之前放入client的回調對象是實作的 MqttCallbackExtended 接口,則MQTT會将我們的回調對象放入 connectActionListener 中 然後由 connectActionListener實作具體的connect
接下來我們不callback 對象改為實作 MqttCallbackExtended這個接口,然後實作下面方法,
@Override
public void connectComplete(boolean reconnect, String serverURI) {
//連接配接成功後調用
client.subscribe(topics,Qos);//具體訂閱代碼
}
就可以解決MQTT重連後無法訂閱的問題。