天天看點

MQTT斷線重連及訂閱消息恢複

問題

采用以下配置

        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重連後無法訂閱的問題。

繼續閱讀