简体   繁体   English

如何使用Eclipse Paho在Java MQTT客户端上接收时发布消息

[英]How to publish a message while receiving on a Java MQTT client using Eclipse Paho

I'm trying to implement some features on an MQTT client in Java with Eclipse Paho. 我正在尝试使用Eclipse Paho在Java中的MQTT客户端上实现某些功能。 The target is to subscribe to a topic and when a message is received, the client send another message on another topic. 目标是订阅主题,当收到消息时,客户端发送另一个主题的另一个消息。

This looks very easy, but I have a weird problem I can't solve. 这看起来很容易,但我有一个奇怪的问题,我无法解决。 Here is my code : 这是我的代码:

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

public class MqttOperations implements MqttCallback {

    MqttClient sampleClient;
    MqttConnectOptions connOpts;

    public MqttOperations() {
    }

    public static void main(String[] args) throws InterruptedException {
        new MqttOperations().launchMqttClient();
    }


    public void launchMqttClient() throws InterruptedException {
         try {
                MemoryPersistence persistence = new MemoryPersistence();
                sampleClient = new MqttClient("tcp://broker.mqttdashboard.com:1883", "iamaclient", persistence);
                connOpts = new MqttConnectOptions();
                connOpts.setCleanSession(true);
                sampleClient.connect(connOpts);
                sampleClient.subscribe("topic/example/ofmessage");
                sampleClient.setCallback(this);

            } catch(MqttException me) {
                System.out.println("reason "+me.getReasonCode());
                System.out.println("msg "+me.getMessage());
                System.out.println("loc "+me.getLocalizedMessage());
                System.out.println("cause "+me.getCause());
                System.out.println("excep "+me);
                me.printStackTrace();
            }
    }


    @Override
    public void connectionLost(Throwable cause) {
        // TODO Auto-generated method stub  

    }

    @Override
    public void messageArrived(String topic, MqttMessage message) throws MqttException
    {
        System.out.println("Received: " + message.toString());  
        try{
            System.out.println("Publishing message: i am the answer");
            MqttMessage ans = new MqttMessage("i am the answer".getBytes());
            ans.setQos(2);
            sampleClient.publish("topic/example/ofanswer", ans);
            System.out.println("Message published");

        }catch(MqttException me){
                System.out.println("reason "+me.getReasonCode());
                System.out.println("msg "+me.getMessage());
                System.out.println("loc "+me.getLocalizedMessage());
                System.out.println("cause "+me.getCause());
                System.out.println("excep "+me);
                me.printStackTrace();
        }

    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {

    }

}

The thing is, this program works only once. 问题是,这个程序只运行一次。 When the message is received, the answer to this message is sent, but it appears that the message "message published" is never displayed on the screen, and the client doesn't receive any other messages. 收到消息后,将发送此消息的答案,但似乎消息“已发布消息”从未显示在屏幕上,并且客户端不会收到任何其他消息。 I have this impression that the line sampleClient.publish("topic/example/ofanswer", ans); 我有这样的印象,即sampleClient.publish("topic/example/ofanswer", ans);sampleClient.publish("topic/example/ofanswer", ans); never finishes its execution. 永远不会完成它的执行。 Does anyone know how it comes and how to solve my problem please? 有谁知道它是怎么来的,请问如何解决我的问题?

I had a similar problem today. 我今天遇到了类似的问题。 When I read an other question with two connections I got it: You need two MqttClient instances. 当我用两个连接读到另一个问题时,我得到了它:你需要两个MqttClient实例。 One for publishing and one for subscribing. 一个用于发布,一个用于订阅。 Unfortunately I found no documentation for that fact. 不幸的是,我没有找到这方面的文件。

By the way. 顺便说说。 In my first implementation with two clients, I gave them the same ids (logically it should be the same connection). 在我第一次使用两个客户端时,我给了它们相同的ID(逻辑上它应该是相同的连接)。 But the second connection disconnects the first one. 但是第二个连接断开了第一个连接。 When I started to use two different ids, it starts to work. 当我开始使用两个不同的ID时,它开始工作。

Dominik Obermaier is right: the problem is that you block in messageArrived. Dominik Obermaier是对的:问题是你阻止了messageArrived。 Specifically, MqttClient.publish waits until a notice of delivery for the message has been received - but the MqttClient work thread never gets to retrieve it, because it's sitting waiting for the very notice in messageArrived! 具体来说,MqttClient.publish等待直到收到消息的传递通知 - 但是MqttClient工作线程永远不会检索它,因为它正在等待messageArrived中的通知!

The two-clients solution works because the other client's work thread is free to retrieve the notice from the socket, but the proper solution is to either publish with QoS 0 from within messageArrived (as QoS 0 messages need no confirmation of delivery) or use an API that does not wait for the message to be delivered, such as MqttTopic.publish. 双客户端解决方案有效,因为其他客户端的工作线程可以自由地从套接字检索通知,但正确的解决方案是从messageArrived中发布QoS 0(因为QoS 0消息不需要确认传递)或使用不等待传递消息的API,例如MqttTopic.publish。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM