>source

일부 애플리케이션에 MQTT 클라이언트 Java 라이브러리를 사용하고 있는데 브로커에 잘못된 방식으로 다시 연결하고 있는 것 같습니다. 지금은 연결, 연결 해제, 게시 및 구독과 같은 MQTT 작업을 처리하는 클래스가 있습니다.

public class MqttConnection {
    private static final String BROKER_ADDRESS= Preferences.getProperty("mqtt-address");
    private static final String BROKER_PORT= Preferences.getProperty("mqtt-port");
    private static final String BROKER_URI= "tcp://" + BROKER_ADDRESS + ":" + BROKER_PORT;
    private static final String VHOST= Preferences.getProperty("mqtt-vhost");
    private static final String USERNAME= Preferences.getProperty("mqtt-username");
    private static final String PASSWORD= Preferences.getProperty("mqtt-password");
    private static MqttClient client;
    private static final Logger logger= LogManager.getLogger(MqttConnection.class);
    static {
        try {
            client= new MqttClient(BROKER_URI, MqttClient.generateClientId());
        } catch (MqttException ex) {
            logger.fatal(ex);
        }
        client.setCallback(new MqttCallback() {
            @Override
            public void connectionLost(Throwable thrwbl) {
                logger.info("MQTT : Perte de connexion...");
                MqttConnection.start();
            }
            @Override
            public void messageArrived(String topic, MqttMessage message) throws Exception {
                //CODE HERE
            }
            @Override
            public void deliveryComplete(IMqttDeliveryToken imdt) { }
        });
    }
    public static void start() {
        connect();
    }
    private static void connect() {
        if (!client.isConnected()) {
            try {
                if (Preferences.getProperty("mqtt-isauth").equalsIgnoreCase("true")) {
                    MqttConnectOptions options= new MqttConnectOptions();
                    String username= (VHOST.equals("")) ? USERNAME : VHOST + ":" + USERNAME;
                    options.setUserName(username);
                    options.setPassword(PASSWORD.toCharArray());
                    client.connect(options);
                } else {
                    client.connect();
                }
                logger.info("MQTT : Connecté au broker.");
            } catch (MqttException ex) {
                logger.fatal(ex);
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    logger.fatal(e);
                }
                connect();
            }
        }
    }
    private static void subscribe() {
        if (client.isConnected()) {
            try {
                client.subscribe("+/SWI1");
            } catch (MqttException e) {
                logger.fatal(e);
            }
        }
    }
}

하지만 재접속을 시도할 때 많은 접속을 여는 것 같고, 브로커 버그를 만든다. MQTT 브로커에 다시 연결하는 가장 좋은 방법은 무엇입니까?

  • 답변 # 1

    사용해 보았습니다.MqttConnectOptions.setAutomaticReconnect(true)그러나 연결 실패 시 성공적으로 다시 연결할 수 없습니다.

    그래서 아래와 같은 code를 사용하여 재연결을 관리하려고 시도하고 작동합니다!

    //make the client nullable and set it to null before to reconnect
    private var mqttClient: MqttAndroidClient?= null
    

    //setup connection options and connect
    private fun setupMQTT(){
        Log.d("mqtt-log", "setup mqtt")
        val serverIP= "192.168.0.198"
        val serverPort= "1883"
        val serverURI= "tcp://${serverIP}:${serverPort}"
        mqttClient= MqttAndroidClient(this, serverURI, "kotlin_client")
        val options= MqttConnectOptions()
        //don't use build-in automaticRecconnect
        options.isAutomaticReconnect= false
        options.connectionTimeout= 0
        options.isCleanSession= false
        try {
            mqttClient!!.connect(options, null, iMqttActionListener)
        } catch (e: MqttException) {
            e.printStackTrace()
            Log.d("mqtt-log", "Exception")
        }
    }
    

    //handle connection action
    val iMqttActionListener= object : IMqttActionListener {
        override fun onSuccess(asyncActionToken: IMqttToken?) {
            Log.d("mqtt-log", "Connection success")
            subscribeMQTT() //some methods for subscribing topics
        }
        override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
            Log.d("mqtt-log", "Connection failure")
            //retry after 3s.
            //its the very important part to retry.
            Handler(Looper.getMainLooper()).postDelayed({
                with(mqttClient!!) {
                    unregisterResources()
                    close()
                    disconnect()
                    setCallback(null)
                }
                mqttClient= null
                setupMQTT()
            },3000)
        }
    }
    

    //when connection is complete try to subscribe topics
    private fun subscribeMQTT(){
        mqttClient?.setCallback(object : MqttCallback {
            override fun messageArrived(topic: String?, message: MqttMessage?) {
                Log.d("mqtt-log", "Receive message: ${message.toString()} from topic: $topic")
            }
            override fun connectionLost(cause: Throwable?) {
                Log.d("mqtt-log", "Connection lost ${cause.toString()}")
                Handler(Looper.getMainLooper()).postDelayed({
                    with(mqttClient!!) {
                        unregisterResources()
                        close()
                        disconnect()
                        setCallback(null)
                    }
                    mqttClient= null
                    setupMQTT()
                },3000)
            }
            override fun deliveryComplete(token: IMqttDeliveryToken?) {
            }
        })
        mqttClient?.subscribe("topic", 1, null, object : IMqttActionListener {
            override fun onSuccess(asyncActionToken: IMqttToken?) {
                Log.d("mqtt-log", "Subscribed to topic")
            }
            override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
                Log.d("mqtt-log", "Failed to subscribe topic")
            }
        })
    }
    

    및 내장setAutomaticReconnect(참)연결이 이미 설정되어 있는 경우에만 다시 연결됩니다. 스스로 재연결을 관리하면 연결이 설정되기 전에 재연결을 트리거할 수 있습니다.

  • 답변 # 2

    다음을 사용할 수 있습니다.MqttConnectOptions.setAutomaticReconnect(true)자동 재연결을 활성화합니다.

  • 이전 javascript : React Router를 사용하여 React.js에서 프로그래밍 방식으로 새 페이지를 만들고 라우팅하는 방법
  • 다음 c# : HTTP 프록시를 통한 양방향 통신