Могу ли я доверять MQTT, когда телефон находится в безопасном режиме? - PullRequest
1 голос
/ 20 февраля 2020

У меня простое клиентское приложение Paho MQTT Android:

public class PahoExampleActivity extends AppCompatActivity {


    MqttAndroidClient mqttAndroidClient;

    final String serverUri = "ssl://myserver:8887";

    String clientId = "ExampleAndroidClient";
    final String subscriptionTopic = "aaa/";
    final String publishTopic = "exampleAndroidPublishTopic";






    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Timber.plant(new  Timber.DebugTree());
        Timber.plant(new FileLoggingTree(this));
        Timber.tag(Utils.TIMBER_TAG).v("starting");


        setContentView(R.layout.activity_main);

        mqttAndroidClient = new MqttAndroidClient(getApplicationContext(), serverUri, clientId);
        mqttAndroidClient.setCallback(new MqttCallbackExtended() {
            @Override
            public void connectComplete(boolean reconnect, String serverURI) {

                if (reconnect) {
                    Timber.tag(Utils.TIMBER_TAG).v("Reconnected to : " + serverURI);
                    // Because Clean Session is true, we need to re-subscribe
                    subscribeToTopic();
                } else {
                    Timber.tag(Utils.TIMBER_TAG).v("Connected to: " + serverURI);

                }
            }

            @Override
            public void connectionLost(Throwable cause) {
                Timber.tag(Utils.TIMBER_TAG).v("The Connection was lost.");

            }

            @Override
            public void messageArrived(String topic, MqttMessage message) throws Exception {
                Timber.tag(Utils.TIMBER_TAG).v("Incoming message: " + new String(message.getPayload()));
            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken token) {

            }
        });

        MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
        mqttConnectOptions.setAutomaticReconnect(true);
        mqttConnectOptions.setCleanSession(false);

        mqttConnectOptions.setKeepAliveInterval(300);
        mqttConnectOptions.setUserName("a");
        mqttConnectOptions.setPassword("a".toCharArray());


        try {
            mqttConnectOptions.setSocketFactory(SocketFactoryMQ.getSocketFactory(this,""));
        } catch (KeyStoreException e) {
            Timber.e ( e);

        } catch (NoSuchAlgorithmException e) {
            Timber.tag(Utils.TIMBER_TAG).e ( e);
        } catch (IOException e) {
            Timber.tag(Utils.TIMBER_TAG).e ( e);
        } catch (KeyManagementException e) {
            Timber.tag(Utils.TIMBER_TAG).e ( e);
        } catch (CertificateException e) {
            Timber.tag(Utils.TIMBER_TAG).e ( e);
        } catch (UnrecoverableKeyException e) {
            Timber.tag(Utils.TIMBER_TAG).e ( e);
        }



        try {
            //addToHistory("Connecting to " + serverUri);
            mqttAndroidClient.connect(mqttConnectOptions, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    DisconnectedBufferOptions disconnectedBufferOptions = new DisconnectedBufferOptions();
                    disconnectedBufferOptions.setBufferEnabled(true);
                    disconnectedBufferOptions.setBufferSize(100);
                    disconnectedBufferOptions.setPersistBuffer(false);
                    disconnectedBufferOptions.setDeleteOldestMessages(false);
                    mqttAndroidClient.setBufferOpts(disconnectedBufferOptions);
                    subscribeToTopic();
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Timber.tag(Utils.TIMBER_TAG).v("Failed to connect to: " + serverUri);
                }
            });


        } catch (MqttException ex){
            ex.printStackTrace();
        }

    }


    public void subscribeToTopic(){
        try {
            mqttAndroidClient.subscribe(subscriptionTopic, 0, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Timber.tag(Utils.TIMBER_TAG).v("Subscribed!");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Timber.tag(Utils.TIMBER_TAG).v("Failed to subscribe");
                }
            });


            mqttAndroidClient.subscribe(subscriptionTopic, 0, new IMqttMessageListener() {
                @Override
                public void messageArrived(String topic, MqttMessage message) throws Exception {
                    // message Arrived!
                    Timber.tag(Utils.TIMBER_TAG).v("Message: " + topic + " : " + new String(message.getPayload()));
                    sendNotification(topic,new String(message.getPayload()));
                }
            });

        } catch (MqttException ex){
            System.err.println("Exception whilst subscribing");
            ex.printStackTrace();
        }
    }




    public void sendNotification(String title, String message) {

        ... 

    }


}

Все отлично работает, когда телефон подключен к зарядному устройству или активен. Мое приложение пропускает сообщения MQTT, когда телефон отключен от зарядного устройства и закрыт (я называю это энергосберегающим режимом). В этой ситуации через некоторое время телефон начинает пропускать MQTT-сообщения. Согласно журналу, полученному с телефона, мы видим, что сообщения появляются при пробуждении телефона:

Thu Feb 20 2020 at 02:41:27:776 pm  Message:  aaa/ : 2
Thu Feb 20 2020 at 02:41:49:537 pm  Message:  aaa/ : 3
Thu Feb 20 2020 at 02:44:26:972 pm  Message:  aaa/ : 2
Thu Feb 20 2020 at 02:44:47:913 pm  Message:  aaa/ : 3
Thu Feb 20 2020 at 02:45:20:876 pm  Message:  aaa/ : 4
Thu Feb 20 2020 at 02:46:01:322 pm  Message:  aaa/ : 5
Thu Feb 20 2020 at 02:46:52:873 pm  Message:  aaa/ : 6
Thu Feb 20 2020 at 02:47:09:993 pm  The Connection was lost.
Thu Feb 20 2020 at 02:54:44:263 pm  Reconnected to : ssl://myserver:8887
Thu Feb 20 2020 at 02:54:44:357 pm  Subscribed!
Thu Feb 20 2020 at 02:54:48:196 pm  MainActivity.onStart
Thu Feb 20 2020 at 02:55:28:465 pm  MainActivity.onStop
Thu Feb 20 2020 at 02:55:33:080 pm  Message:  aaa/ : 12
Thu Feb 20 2020 at 02:57:35:070 pm  Message:  aaa/ : 13
Thu Feb 20 2020 at 02:58:30:264 pm  The Connection was lost.
Thu Feb 20 2020 at 03:02:54:001 pm  Reconnected to : ssl://myserver:8887
Thu Feb 20 2020 at 03:02:54:103 pm  Subscribed!

Сообщения 7-11 просто не дошли до моего устройства. Как решить эту проблему?

UPD

После изменения QOS 0 на QOS 1 я получил все сообщения. Сообщения, начинающиеся с 10, пришли одновременно с некоторой задержкой. С первого взгляда 5 мин. задержка не имеет значения, но я не уверен, насколько большой это может быть. Например 30 мин. задержка не подходит.

Thu Feb 20 2020 at 06:20:54:411 pm  Message: aaa/ : 2
Thu Feb 20 2020 at 06:21:16:221 pm  Message: aaa/ : 3
Thu Feb 20 2020 at 06:21:48:173 pm  Message: aaa/ : 4
Thu Feb 20 2020 at 06:22:29:642 pm  Message: aaa/ : 5
Thu Feb 20 2020 at 06:23:21:571 pm  Message: aaa/ : 6
Thu Feb 20 2020 at 06:24:23:327 pm  Message: aaa/ : 7
Thu Feb 20 2020 at 06:25:34:278 pm  Message: aaa/ : 8
Thu Feb 20 2020 at 06:26:56:309 pm  Message: aaa/ : 9
Thu Feb 20 2020 at 06:27:16:408 pm  The Connection was lost.
Thu Feb 20 2020 at 06:32:27:667 pm  MainActivity.onStart
Thu Feb 20 2020 at 06:32:37:320 pm  Reconnected to : ssl://myserver:8887
Thu Feb 20 2020 at 06:32:37:390 pm  Message: aaa/ : 10
Thu Feb 20 2020 at 06:32:37:442 pm  Subscribed!
Thu Feb 20 2020 at 06:32:37:450 pm  Message: aaa/ : 11
Thu Feb 20 2020 at 06:32:37:498 pm  Message: aaa/ : 12
Thu Feb 20 2020 at 06:32:38:084 pm  MainActivity.onStop
Thu Feb 20 2020 at 06:34:02:431 pm  Message: aaa/ : 13

1 Ответ

1 голос
/ 20 февраля 2020

Вы подписались на topi c в QOS 0, что означает "огонь и забудь", не будет предпринято никаких усилий, чтобы убедиться, что сообщение действительно доставлено.

mqttAndroidClient.subscribe(subscriptionTopic, 0, new IMqttMessageListener() {...

Если вы хотите быть уверены Для доставки вам необходимо использовать QOS 1 (как минимум один раз) или QOS 2 (один раз и только один раз)

mqttAndroidClient.subscribe(subscriptionTopic, 1, new IMqttMessageListener() {...
...