Java 具有qos 2的发布者发布从代理或订阅方获得确认

Java 具有qos 2的发布者发布从代理或订阅方获得确认,java,eclipse,mqtt,mosquitto,paho,Java,Eclipse,Mqtt,Mosquitto,Paho,我对qos有点困惑, 我读到关于qos的文章 如果qos设置为2,那么代理/客户机将使用四步握手准确地传递消息一次 所以qos 2确认消息是在代理上发布的,而不是由订阅者(客户端)接收的。 或 消息由订阅者接收 或 对于确认,我们需要建立像publisher这样的应用程序,发布主题为“数据”的消息,订阅主题为“确认”,订阅者需要发布主题为“确认”的确认,即收到主题为“数据”的消息 我创建了一个用于发布数据的java类和另一个用于订阅的类 出版者 在下面的代码中,我尝试在qos 2上发布,在del

我对qos有点困惑, 我读到关于qos的文章 如果qos设置为2,那么代理/客户机将使用四步握手准确地传递消息一次

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

对于确认,我们需要建立像publisher这样的应用程序,发布主题为“数据”的消息,订阅主题为“确认”,订阅者需要发布主题为“确认”的确认,即收到主题为“数据”的消息

我创建了一个用于发布数据的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();
            }
        }
//                 


    }


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

从上面的链接


QoS2,仅一次:消息始终仅传递一次。消息必须本地存储在发送方,直到发送方收到接收方已发布消息的确认。存储该消息是为了防止必须再次发送该消息。QoS2是最安全但最慢的传输模式。

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

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

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

deliveryComplete
回调仅表示发布者已完成向代理发送消息。另外,如果消息已经传递,则
token.getMessage()
将返回null,这将解释您提到的异常(我不得不在这里猜测,因为您没有包含异常)


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

,请在问题中包括异常,这样我们就不会猜测实际发生了什么。对于异常,它是token。getMessage()返回null,qos为1和2,这意味着如果我得到null,那么我应该将消息标记为已传递。从您的回答来看,我认为发布者和订阅者是独立的,代理将负责消息的客户端。谢谢你提供的细节,我读了很多文件,我很困惑