当手机处于电源安全模式时,我可以信任 MQTT [英] Can I trust MQTT when phone in power safe mode

查看:74
本文介绍了当手机处于电源安全模式时,我可以信任 MQTT的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的 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";@覆盖protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Timber.plant(new Timber.DebugTree());Timber.plant(new FileLoggingTree(this));Timber.tag(Utils.TIMBER_TAG).v("开始");setContentView(R.layout.activity_main);mqttAndroidClient = new MqttAndroidClient(getApplicationContext(), serverUri, clientId);mqttAndroidClient.setCallback(new MqttCallbackExtended() {@覆盖公共无效connectComplete(布尔重新连接,字符串serverURI){如果(重新连接){Timber.tag(Utils.TIMBER_TAG).v("重新连接到:" + serverURI);//因为Clean Session为true,我们需要重新订阅订阅主题();} 别的 {Timber.tag(Utils.TIMBER_TAG).v("连接到:" + serverURI);}}@覆盖public void connectionLost(Throwable 原因) {Timber.tag(Utils.TIMBER_TAG).v("连接丢失.");}@覆盖public void messageArrived(String topic, MqttMessage message) 抛出异常 {Timber.tag(Utils.TIMBER_TAG).v("传入消息:" + new String(message.getPayload()));}@覆盖public void deliveryComplete(IMqttDeliveryToken 令牌){}});MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();mqttConnectOptions.setAutomaticReconnect(true);mqttConnectOptions.setCleanSession(false);mqttConnectOptions.setKeepAliveInterval(300);mqttConnectOptions.setUserName("a");mqttConnectOptions.setPassword("a".toCharArray());尝试 {mqttConnectOptions.setSocketFactory(SocketFactoryMQ.getSocketFactory(this,""));} catch (KeyStoreException e) {木材.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);}尝试 {//addToHistory("连接到" + serverUri);mqttAndroidClient.connect(mqttConnectOptions, null, new IMqttActionListener() {@覆盖public void onSuccess(IMqttToken asyncActionToken) {DisconnectedBufferOptions disconnectedBufferOptions = new DisconnectedBufferOptions();disconnectedBufferOptions.setBufferEnabled(true);disconnectedBufferOptions.setBufferSize(100);disconnectedBufferOptions.setPersistBuffer(false);disconnectedBufferOptions.setDeleteOldestMessages(false);mqttAndroidClient.setBufferOpts(disconnectedBufferOptions);订阅主题();}@覆盖public void onFailure(IMqttToken asyncActionToken, Throwable 异常) {Timber.tag(Utils.TIMBER_TAG).v("连接失败:" + serverUri);}});} catch (MqttException ex){ex.printStackTrace();}}公共无效订阅主题(){尝试 {mqttAndroidClient.subscribe(subscriptionTopic, 0, null, new IMqttActionListener() {@覆盖public void onSuccess(IMqttToken asyncActionToken) {Timber.tag(Utils.TIMBER_TAG).v("订阅了!");}@覆盖public void onFailure(IMqttToken asyncActionToken, Throwable 异常) {Timber.tag(Utils.TIMBER_TAG).v("订阅失败");}});mqttAndroidClient.subscribe(subscriptionTopic, 0, new IMqttMessageListener() {@覆盖public void messageArrived(String topic, MqttMessage message) 抛出异常 {//消息到达!Timber.tag(Utils.TIMBER_TAG).v("Message:" + topic +" :" + new String(message.getPayload()));sendNotification(topic,new String(message.getPayload()));}});} catch (MqttException ex){System.err.println("订阅时出现异常");ex.printStackTrace();}}公共无效发送通知(字符串标题,字符串消息){...}}

当手机连接到充电器或处于活动状态时,一切正常.我的申请错过手机与充电器断开连接并关闭时的 MQTT 消息(我称之为电源安全模式).在这种情况下,一段时间后手机开始错过 MQTT 消息.根据手机的日志,我们可以看到手机唤醒时出现的消息:

2020 年 2 月 20 日星期四下午 02:41:27:776 消息:aaa/:22020 年 2 月 20 日星期四下午 02:41:49:537 消息:aaa/:32020 年 2 月 20 日星期四下午 02:44:26:972 消息:aaa/:22020 年 2 月 20 日星期四下午 02:44:47:913 消息:aaa/:32020 年 2 月 20 日星期四下午 02:45:20:876 消息:aaa/:42020 年 2 月 20 日星期四下午 02:46:01:322 消息:aaa/:52020 年 2 月 20 日星期四下午 02:46:52:873 消息:aaa/:62020 年 2 月 20 日星期四下午 02:47:09:993 连接丢失.2020 年 2 月 20 日星期四下午 02:54:44:263 重新连接到:ssl://myserver:88872020 年 2 月 20 日星期四下午 02:54:44:357 订阅!2020 年 2 月 20 日星期四下午 02:54:48:196 MainActivity.onStart2020 年 2 月 20 日星期四下午 02:55:28:465 MainActivity.onStop2020 年 2 月 20 日星期四下午 02:55:33:080 消息:aaa/:122020 年 2 月 20 日星期四下午 02:57:35:070 消息:aaa/:132020 年 2 月 20 日星期四下午 02:58:30:264 连接丢失.2020 年 2 月 20 日星期四下午 03:02:54:001 重新连接到:ssl://myserver:88872020 年 2 月 20 日星期四下午 03:02:54:103 订阅!

消息 7-11 未到达我的设备.如何解决这个问题?

更新

QOS 0 更改为 QOS 1 后,我收到了所有消息.在一些延迟之后,从 10 开始的消息同时出现.乍一看 5 分钟.延迟无关紧要,但我不确定延迟有多大.例如30分钟.延迟不合适.

2020 年 2 月 20 日星期四下午 06:20:54:411 消息:aaa/:22020 年 2 月 20 日星期四下午 06:21:16:221 消息:aaa/:32020 年 2 月 20 日星期四下午 06:21:48:173 消息:aaa/:42020 年 2 月 20 日星期四下午 06:22:29:642 消息:aaa/:52020 年 2 月 20 日星期四下午 06:23:21:571 消息:aaa/:62020 年 2 月 20 日星期四下午 06:24:23:327 消息:aaa/:72020 年 2 月 20 日星期四下午 06:25:34:278 消息:aaa/:82020 年 2 月 20 日星期四下午 06:26:56:309 消息:aaa/:92020 年 2 月 20 日星期四 06:27:16:408 pm 连接丢失.2020 年 2 月 20 日星期四下午 06:32:27:667 MainActivity.onStart2020 年 2 月 20 日星期四下午 06:32:37:320 重新连接到:ssl://myserver:88872020 年 2 月 20 日星期四下午 06:32:37:390 消息:aaa/:102020 年 2 月 20 日星期四下午 06:32:37:442 订阅!2020 年 2 月 20 日星期四下午 06:32:37:450 消息:aaa/:112020 年 2 月 20 日星期四下午 06:32:37:498 消息:aaa/:122020 年 2 月 20 日星期四下午 06:32:38:084 MainActivity.onStop2020 年 2 月 20 日星期四下午 06:34:02:431 消息:aaa/:13

解决方案

您已在 QOS 0 订阅主题即发即忘",将不做任何努力来确保消息真正送达.

>

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

如果您想要有保证的交付,您需要使用 QOS 1(至少一次)或 QOS 2(一次且仅一次)

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

I have simple Paho MQTT Android client application:

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) {

        ... 

    }


}

Everything works fine when phone is connected to charger or active. My application miss MQTT messages when phone is disconnected from charger and is closed (I call it power safe mode). In this situation after some time phone starts to miss MQTT messages. According to log taken from phone we can see that messages appear when phone is waked up:

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!

Messages 7-11 just not reached my device. How to solve this problem?

UPD

After change QOS 0 to QOS 1 I got all messages. Messages starting from 10 came at the same time after some delay. From first glance 5 min. delay is not relevant, but I'm not sure how big delay it might be. For example 30 min. delay is not appropriate.

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

解决方案

You have subscribed to the topic at QOS 0 which is "fire and forget", no effort will be made to make sure the message is actually delivered.

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

If you want assured delivery you need to use QOS 1 (At least once) or QOS 2 (Once and only once)

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

这篇关于当手机处于电源安全模式时,我可以信任 MQTT的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆