【问题标题】:publisher publishing with qos 2 get the acknowledge from broker or subcriber使用 qos 2 发布的发布者获得代理或订阅者的确认
【发布时间】:2016-05-21 17:35:03
【问题描述】:

我对 qos 有点困惑, 我读到关于 qos 是 如果 qos 设置为 2,那么代理/客户端将使用四步握手将消息传递一次。

所以 qos 2 确认消息是在代理上发布的,而不是订阅者(客户端)接收到的。 或者 订阅者收到消息 或

对于确认,我们需要建立应用程序,例如发布者将发布带有主题(例如“DATA”)的消息,并将订阅主题(例如“ACK”),而订阅者需要发布对主题“ACK”的确认,该消息是收到主题“数据”

我创建了一个用于发布数据的 java 类和另一个用于订阅的类 出版商

在以下代码中,我尝试在 qos 2 和 deliveryComplete 函数中发布异常,当我尝试使用 qos 0 getMessage() 时尝试 getMessage() 没有给出任何异常。

public class PublishMe implements MqttCallback{
    MqttClient myClient;
    MqttClient myClientPublish;
    MqttConnectOptions connOpt;
    MqttConnectOptions connOptPublish;
    static final String BROKER_URL = "tcp://Ehydromet-PC:1883";

    static Boolean msgACK=false;    
    public static void main(String[] args) {
        PublishMe smc = new PublishMe();
        smc.runClient();
    }
    @Override
    public void connectionLost(Throwable t) {
        System.out.println("Connection lost!");
    }

        @Override
        public void messageArrived(String string, MqttMessage message) throws Exception {
                System.out.println("-------------------------------------------------");
        System.out.println("| Topic:" + string);
        System.out.println("| Message: " + new String(message.getPayload()));
        System.out.println("-------------------------------------------------");

        }
/**
     * 
     * deliveryComplete
     * This callback is invoked when a message published by this client
     * is successfully received by the broker.
     * 
     * @param token
     */
    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
       try{
        System.out.println("Message delivered successfully to topic : \"" + token.getMessage().toString() + "\".");
       }catch(Exception ex){
        System.out.println(ex.getCause()+" -- "+ex.getLocalizedMessage()+" -- "+ex.getMessage()+" -- " );      
               }

       }

    public void runClient() {
        connOpt = new MqttConnectOptions();
        connOpt.setCleanSession(false);
        connOpt.setKeepAliveInterval(0);

                connOptPublish= new MqttConnectOptions();
        connOptPublish.setCleanSession(false);
        connOptPublish.setKeepAliveInterval(0);

// Connect to Broker
        try {
            myClient = new MqttClient(BROKER_URL, "pahomqttpublish11");
            myClient.setCallback(this);
            myClient.connect(connOpt);

                        myClientPublish= new MqttClient(BROKER_URL, "pahomqttpublish42");
            myClientPublish.setCallback(this);
            myClientPublish.connect(connOptPublish);

        } catch (MqttException e) {
            e.printStackTrace();
            System.exit(-1);
        }

        System.out.println("Connected to " + BROKER_URL);

        String myTopic = "sample";
//                String myTopic = "receiveDATA2";
                MqttTopic topic = myClientPublish.getTopic(myTopic);

        // publish messages if publisher
        if (publisher) {

                    int i=1;
            while(true){
                                String pubMsg = "sample msg "+i;

                MqttMessage message = new MqttMessage(pubMsg.getBytes());
                                System.out.println(message);
                                message.setQos(2);
                                message.setRetained(false);

                                // Publish the message
                                MqttDeliveryToken token = null;
                                try {
                    // publish message to broker
                    token = topic.publish(message);
                    // Wait until the message has been delivered to the broker
                    token.waitForCompletion();
                                        msgACK=false;
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }           
        }
    }


}

以下是订阅者

public class Mqttsample implements MqttCallback{
    MqttClient myClient;
    MqttClient myClientPublish;
    MqttConnectOptions connOpt;
MqttConnectOptions connOptPublish;
    static final String BROKER_URL = "tcp://Ehydromet-PC:1883";
    // the following two flags control whether this example is a publisher, a subscriber or both
    static final Boolean subscriber = true;
    static final Boolean publisher = true;
        public static void main(String[] args) {


        Mqttsample smc = new Mqttsample();
        smc.runClient();
    }
       @Override
    public void connectionLost(Throwable t) {
        System.out.println("Connection lost!");
        // code to reconnect to the broker would go here if desired
    }

        @Override
        public void messageArrived(String string, MqttMessage message) throws Exception {
        //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
                System.out.println("| Topic:" + string+"| Message: " + new String(message.getPayload()));

        }

    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
        try{
            System.out.println("Pub complete" + new String(token.getMessage().getPayload()));
        }
        catch(Exception ex ){
            System.out.println("delivery Error "+ex.getMessage());
        }
       }



    public void runClient() {
        connOpt = new MqttConnectOptions();
        connOpt.setCleanSession(false);
        connOpt.setKeepAliveInterval(0);

                connOptPublish= new MqttConnectOptions();
        connOptPublish.setCleanSession(false);
        connOptPublish.setKeepAliveInterval(0);

// Connect to Broker
        try {
            myClient = new MqttClient(BROKER_URL, "pahomqttpublish");
            myClient.setCallback(this);
            myClient.connect(connOpt);

                        myClientPublish= new MqttClient(BROKER_URL, "pahomqttsubscribe");
            myClientPublish.setCallback(this);
            myClientPublish.connect(connOptPublish);

        } catch (MqttException e) {
            e.printStackTrace();
            System.exit(-1);
        }

        System.out.println("Connected to " + BROKER_URL);


        // subscribe to topic if subscriber
        if (subscriber) {
            try {
                            //String myTopicACK = M2MIO_DOMAIN + "/" + "ACK" + "/" + M2MIO_THING;
                            String myTopicACK = "sample";
                           // MqttTopic topicACK = myClient.getTopic(myTopicACK);
                int subQoS = 2;

                myClient.subscribe(myTopicACK, subQoS);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
//                 


    }


}

我如何确保订阅者已收到消息,我应该在发布者代码中实现什么。

http://www.eclipse.org/paho/files/mqttdoc/Cclient/qos.html 从上面的链接

QoS2,Exactly once:消息总是只传递一次。消息必须本地存储在发送方,直到发送方收到消息已由接收方发布的确认。消息被存储以防必须再次发送消息。 QoS2 是最安全但最慢的传输模式。

【问题讨论】:

  • 再次,请在问题中包含例外情况,这样我们就不会猜测实际发生了什么

标签: java eclipse mqtt mosquitto paho


【解决方案1】:

正如您所确定的,较高的 QOS 级别仅描述客户端(发布者或订阅者)和代理之间的消息传递,而不是端到端发布者到订阅者。

这是经过深思熟虑的,因为作为发布/订阅协议,没有办法知道一个主题可能有多少订阅者。可以有 0 到 n 之间的任何数字。发布者和订阅者也可以在不同的 QOS 级别与主题交互(发布者可以在 QOS 2 发布,订阅者可以在 QOS 0 订阅)。消息也可以作为保留消息发布,这样最后保留的消息将始终传递给新订阅的客户端。

客户端上满足 QOS 合同的所有存储都应由您正在使用的 MQTT 库处理(在本例中为 Paho)

deliveryComplete 回调仅表明发布者已完成向代理发送消息。 doc 还表示,如果消息已发送,token.getMessage() 将返回 null,这将解释您提到的异常(我必须在这里猜测,因为您没有包含异常)。

如果您的应用程序架构确实需要端到端的消息确认,那么您将需要实现类似于您所描述的内容。但是为了确保它正常工作,您应该在消息的有效负载中包含一个消息 ID,并且确认消息应该包含这个,并且可能通过某种方式来识别哪个订阅者正在回复,以确保您知道谁收到了消息。我会使用这样的东西的唯一原因是如果有时间要求来确认消息。如果时间不是相关因素,那么请考虑使用 持久会话 来确保如果消息在发布时断开连接,则在重新连接时将消息传递给订阅客户端。

【讨论】:

  • 对不起,它是 token.getMessage() 返回 null 和 qos 1 和 2 的异常,这意味着如果我得到 null,那么我应该将消息标记为已传递。从您的回答中,我认为发布者和订阅者是独立的,经纪人会照顾客户的消息。感谢您提供的详细信息,我阅读了很多文档,但我很困惑
猜你喜欢
  • 1970-01-01
  • 2016-12-14
  • 1970-01-01
  • 2019-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-28
  • 1970-01-01
相关资源
最近更新 更多