那些年用EMQ踩過的坑
前提
語言用的是Java,包是org.eclipse.paho.client.mqttv3這個,MQ是EMQ。
坑一
客戶端ID相同,導致互相擠下線
場景
公司有很多場景用到MQTT,比如移動端、Java後臺、前端JS、流水線C#程式、各類物聯網硬體Python指令碼等等
很多同事使用的時候,如果進行連線的clientID有衝突的話,會導致已經連線的客戶端斷開連線,而這個時候如果客戶端的回撥裡面做了斷線重連處理的話,就會變成2個客戶端一直在斷線重連...斷線重連...斷線重連...
解決方案:
既然問題是客戶端ID相同,那就讓客戶端ID不相同即可。
比如給客戶端ID加UUID字尾,或者加時間戳字尾之類的,只要能確保不重複即可。
//客戶端 MqttClient testClient = new MqttClient("主題名稱","testClient_"+UUID.randomUUID().toString()); //配置 MqttConnectOptions options = new MqttConnectOptions(); options = new MqttConnectOptions(); options.setCleanSession(true);//設定清除會話資訊 options.setUserName("使用者名稱");//設定使用者名稱 options.setPassword("密碼".toCharArray());//設定密碼 testClient.setCallback(new TestCallback());//回撥 testClient.connect(options);//連線
坑二
回撥類報錯引發的客戶端斷線
場景
當我們的客戶端訂閱了某個主題,該主題收到訊息後,就會進到messageArrived方法。
public void messageArrived(String topic, MqttMessage message) throws Exception { // subscribe後得到的訊息會執行到這裡面 // 時間格式轉換 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("接收訊息時間 : " + sdf.format(new Date())); System.out.println("接收訊息主題 : " + topic); System.out.println("接收訊息Qos : " + message.getQos()); System.out.println("接收訊息內容 : " + new String(message.getPayload())); }
一般我們傳送和接收到的訊息都是JSON格式的字串,然後會在這個方法裡面做業務邏輯處理。
當我們收到的訊息內容不符合預期的格式時,而我們又未做相應的處理時,就會報錯丟擲異常,從而導致接收到該訊息的客戶端斷線。
如果只是普通的程式碼邏輯問題,只需要打個斷點看看具體問題具體分析,然後處理即可。
如果是因為傳送訊息方使用了Retained,導致的一訂閱收到訊息即報錯,觸發重連後重新訂閱又報錯的死迴圈的話。
有可能是在18083控制檯傳送的測試資料,預設被勾選了Retained
也可能是程式碼裡面傳送訊息設定了Retained
//第四個引數retained
testClient.publish(topic, payload, qos, retained);
解決方案:
用任一客戶端往有問題的主題傳送一條空訊息,並設定Retained為true,即可清除該主題所保留的最後一條設定了Retained的異常訊息。
testClient.publish("有問題的主題", "".getBytes(), 0, true);
坑三
傳送的訊息內容太長,導致客戶端斷線
場景
客戶端往某個主題傳送訊息,訊息內容太長導致一執行傳送操作,客戶端就掉線。
原因是EMQ預設的訊息長度是64K(65536位元組),一旦超過就會出問題。
解決方案:
根據版本的不同,找到對應的配置檔案,修改對應的配置即可,最高為256MB。
如1.x版本的EMQ則在安裝目錄的/emqttd/etc/emqttd.config,修改其中的
如2.x版本的EMQ則在安裝目錄的/emqttd/etc/emqttd.conf,修改其中的
也可能在安裝目錄的/emqttd/etc/emq.conf,修改其中的
然後重啟EMQ即可。
坑四
未完。。。待編輯。。。
注:僅供自己學習,記錄問題和參考,若有帶來誤解和不便請見諒,共勉!