簡體   English   中英

我如何知道ACK對應於MQTT上的哪個發布消息?

[英]How can I tell an ACK corresponds to which publish message on MQTT?

我在與Mqtt paho司機爭吵...

每當接收到我的發布時,我就使用IMqttDeliveryToken從服務器獲取確認。

為了將其與實際的發布消息進行比較,我在MqttMessage上設置了一個ID,以便從IMqttDeliveryToken檢索它。但是它不起作用... IMqttDeliveryToken.getMessageId()返回一個不正確的ID,當我當QoS不同於0時,嘗試在IMqttDeliveryToken.getMessage()之后獲取ID,它將返回NPE。

閱讀Javadoc之后,我讀到它是通常的行為:

在傳遞郵件之前,將返回正在傳遞的郵件。 郵件發送完畢后,將返回null。

這使我想到另一個問題...在Broker發送確認之后,是否真的調用了deliveryComplete()方法?

這是我的代碼:

client.setCallback(new MqttCallback() {
    @Override
    public void connectionLost(Throwable thrwbl) { }

    @Override
    public void messageArrived(String string, MqttMessage mm) throws Exception { }

    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
        try {
            System.out.println("Message ID from getMessageId() method : " + token.getMessageId());
            MqttMessage message = token.getMessage();
            System.out.println("Message ID from getMessage() method : " + message.getId());
        } catch (MqttException ex) {
            System.out.println(ex);
        } catch (Exception ex) {
            System.out.println(ex);
        }
    }
});

MqttMessage message = new MqttMessage();
message.setId(76);
message.setPayload("pouet".getBytes());
message.setQos(0);

client.publish("TEST", message);

QoS為0時:

Message ID from getMessageId() method : 1
Message ID from getMessage() method : 76

QoS為1時:

Message ID from getMessageId() method : 1
java.lang.NullPointerException

如git MqttMessage.java中所述

/**
 * This is only to be used internally to provide the MQTT id of a message
 * received from the server.  Has no effect when publishing messages.
 * @param messageId
 */
public void setId(int messageId) {
    this.messageId = messageId;
}

發布消息時不使用此位置。 現在,要了解為什么getMessageId()方法中的消息ID發生了:1,請看下面的內容。

public IMqttDeliveryToken publish(String topic, MqttMessage message, Object userContext, IMqttActionListener callback) throws MqttException,
            MqttPersistenceException {
        final String methodName = "publish";
        //@TRACE 111=< topic={0} message={1}userContext={1} callback={2}
        log.fine(CLASS_NAME,methodName,"111", new Object[] {topic, userContext, callback});

        //Checks if a topic is valid when publishing a message.
        MqttTopic.validate(topic, false/*wildcards NOT allowed*/);

        MqttDeliveryToken token = new MqttDeliveryToken(getClientId());
        token.setActionCallback(callback);
        token.setUserContext(userContext);
        token.setMessage(message);
        token.internalTok.setTopics(new String[] {topic});

        MqttPublish pubMsg = new MqttPublish(topic, message);
        comms.sendNoWait(pubMsg, token);

        //@TRACE 112=<
        log.fine(CLASS_NAME,methodName,"112");

        return token;
    }

MqttDeliveryToken此處未設置消息ID。創建發布MqttPublish實例時,該實例內部將多級擴展到MqttWireMessage.java,並且默認情況下將其設置為0。

public MqttWireMessage(byte type) {
        this.type = type;
        // Use zero as the default message ID.  Can't use -1, as that is serialized
        // as 65535, which would be a valid ID.
        this.msgId = 0;
    }

當在ClientState.java中調用最終發送以進行mqtt發布時,將轉發具有msgId = 0的MqttWireMessage實例(內部MqttPublish是從上述代碼發送的),由於此條件,如果if條件為true,則調用getNextMessageId()返回1(因為這是第一條消息,否則它將根據最后一個msg id返回后續值),並設置為令牌,該令牌在您的代碼中正在deliveryComplete()中進行跟蹤。

public void send(MqttWireMessage message, MqttToken token) throws MqttException {
        final String methodName = "send";
        if (message.isMessageIdRequired() && (message.getMessageId() == 0)) {
            message.setMessageId(getNextMessageId());
        }
        if (token != null ) {
            try {
                token.internalTok.setMessageID(message.getMessageId());
            } catch (Exception e) {
            }
        }

        /////......
    }

回答您的下一個查詢:在Broker發送確認后,是否真的調用了deliveryComplete()方法---是的!

從這小段代碼調用完成的交付。

private void handleActionComplete(MqttToken token)
            throws MqttException {
        final String methodName = "handleActionComplete";
        synchronized (token) {
            // @TRACE 705=callback and notify for key={0}
            log.fine(CLASS_NAME, methodName, "705", new Object[] { token.internalTok.getKey() });
            if (token.isComplete()) {
                // Finish by doing any post processing such as delete 
                // from persistent store but only do so if the action
                // is complete
                clientState.notifyComplete(token);
            }

            // Unblock any waiters and if pending complete now set completed
            token.internalTok.notifyComplete();

            if (!token.internalTok.isNotified()) {
                // If a callback is registered and delivery has finished 
                // call delivery complete callback. 
                if ( mqttCallback != null 
                    && token instanceof MqttDeliveryToken 
                    && token.isComplete()) {
                        mqttCallback.deliveryComplete((MqttDeliveryToken) token);
                }
                // Now call async action completion callbacks
                fireActionEvent(token);
            }

            // Set notified so we don't tell the user again about this action.
            if ( token.isComplete() ){
               if ( token instanceof MqttDeliveryToken || token.getActionCallback() instanceof IMqttActionListener ) {
                    token.internalTok.setNotified(true);
                }
            }



        }
    }

即,一旦收到確認,即notifyComplete完成,就設置標志,調用deliveryComplete方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM