首页 新闻 会员 周边

MQTT怎么避免重复订阅?

0
悬赏园豆:30 [待解决问题]

MQTT里避免重复订阅时用到的字段sessionPresent,为什么我测试的 sessionPresent 全是 false,(cleanSession=false)

        MqttClient client = new MqttClient("tcp://localhost:1883", "push");
        MqttConnectOptions options = new MqttConnectOptions();
        options.setUserName("aaaaaa");
        options.setPassword("aaaaa".toCharArray());
        options.setCleanSession(false);
        IMqttToken iMqttToken = client.connectWithResult(options);
        iMqttToken.waitForCompletion();
        boolean sessionPresent = iMqttToken.getSessionPresent();
        System.out.println("firstResult: " + sessionPresent);  //  第一次访问返回false  正常
        MqttMessage message = new MqttMessage();
        client.publish("tt", "zxzx".getBytes(), 1, false);
        client.disconnect();

        IMqttToken secondToken = client.connectWithResult(options);
        secondToken.waitForCompletion();
        boolean secondResult = secondToken.getSessionPresent();
        System.out.println("secondResult: " + secondResult); // 第二次不是应该返回 true 了吗?为什么还是false
五毒不侵滴bug的主页 五毒不侵滴bug | 初学一级 | 园豆:163
提问于:2023-07-28 19:22
< >
分享
所有回答(3)
0

在MQTT协议中,用于避免重复订阅的字段并不是sessionPresent,而是cleanSession选项。

在你提供的代码中,options.setCleanSession(false)表示使用一个持久的会话连接,这意味着当客户端断开连接后,MQTT服务器会保持客户端的订阅和会话信息。当你第二次连接时,应该返回true表示服务器在断开连接后仍然保持了会话信息。

然而,你的代码在连接第二次时似乎没有成功获取到持久会话信息,导致secondResult一直为false。这可能是因为你在第二次连接之前,没有正确处理会话状态。

要在客户端重新获取之前的会话信息,可以使用MqttConnectOptions中的setCleanSession(false)选项,并在连接之前设置以下两个选项:

options.setCleanSession(false);
options.setAutomaticReconnect(true);

这样,当客户端重新连接时,它会尝试恢复之前的会话信息,并返回sessionPresenttrue

请确保你的MQTT服务器配置正确,并支持持久会话的功能。此外,你可能还需要检查你的代码以确保在连接前正确初始化MqttClient对象。

lanedm | 园豆:2381 (老鸟四级) | 2023-07-30 21:09
0

在MQTT协议中,sessionPresent字段用于指示是否存在现有的会话(Session)。当客户端连接到Broker时,Broker会检查是否存在先前建立的会话,如果存在则返回sessionPresent=true,否则返回sessionPresent=false。

根据您提供的代码,您在第一次连接时将options.setCleanSession(false),这意味着您正在使用持久化会话(persistent session)。在持久化会话模式下,即使客户端断开连接后再次连接,Broker仍然会保存先前的会话状态,包括订阅信息等。

因此,当您第一次连接时,如果不存在先前建立的会话,则sessionPresent为false,这是正常的。然后,您发布了一条消息并断开连接。

接着,您再次连接时,由于options.setCleanSession(false),您将恢复先前的会话状态,包括订阅信息。在这种情况下,sessionPresent应该为true,因为现在存在先前建立的会话。

然而,根据您提供的代码和描述,sessionPresent在第二次连接时仍然为false,这可能有几个原因:

Broker配置问题:可能是Broker配置问题导致持久化会话未正确保存。

客户端标识符(Client Identifier):MQTT要求客户端标识符在整个MQTT代理中必须是唯一的。如果您使用相同的客户端标识符连接两次,Broker可能会将其视为同一个会话,导致sessionPresent为false。请确保在两次连接时使用不同的客户端标识符。

代理(Broker)的问题:可能是特定MQTT代理实现的问题,尽管这种情况较少见。

为了更好地排查问题,建议您尝试以下步骤:

确保Broker配置正确,并支持持久化会话。
尝试在第二次连接时使用不同的客户端标识符。
尝试在不同的MQTT代理中进行测试,以验证代理是否有问题。
如果问题仍然存在,您可能需要查看MQTT代理的日志以获取更多关于连接和会话状态的信息,或者查阅特定MQTT代理的文档以了解更多有关持久化会话的详细信息。

Technologyforgood | 园豆:5992 (大侠五级) | 2023-07-30 21:29
0

在MQTT中,sessionPresent字段是在连接时的响应中使用的标志,用于指示服务器是否已经存储了客户端的会话状态。

根据MQTT协议的规定,当客户端连接到MQTT服务器时,如果设置了cleanSessionfalse,表示客户端需要继续使用之前的会话状态。如果服务器已经存储了该客户端的会话状态,则在连接响应中,sessionPresent字段会被设置为true,表示会话已经存在。如果服务器上不存在该客户端的会话状态,或者之前的会话已被清除,sessionPresent字段将会被设置为false

在你的代码中,当第一次连接时,你设置了cleanSessionfalse,并且通过getSessionPresent()方法获取了sessionPresent字段的值,结果为false,这是符合预期的,因为这是第一次连接,之前还没有会话状态。

然后,你断开了连接,然后进行第二次连接,依然设置了cleanSessionfalse,但是却得到了sessionPresentfalse的结果。这可能是因为在第一次连接断开后,服务器可能已经清除了之前的会话状态,导致第二次连接时,服务器没有找到对应的会话状态,所以sessionPresent被设置为false

如果你希望第二次连接时能够得到sessionPresenttrue的结果,你需要确保第一次连接断开后服务器没有清除对应的会话状态。

NotoChen | 园豆:401 (菜鸟二级) | 2023-08-02 10:47
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册