所以qos 2确认消息是在代理上发布的,而不是由订户(客户端)接收的。 要么 订阅者收到消息 或
对于确认我们应该建立像发布者这样的应用程序将发布带有主题的消息,例如" DATA"并将订阅一个主题,例如" ACK"并且订户需要发布关于主题的确认" ACK"在主题" DATA"上收到该消息
我创建了一个用于发布数据的java类和另一个用于订阅的类 出版商
在下面的代码中我尝试在qos 2和deliveryComplete函数中发布我在尝试使用getMessage()时遇到异常,当我尝试使用qos时,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,恰好一次:消息始终只发送一次。消息必须本地存储在发送方,直到发送方收到消息已由接收方发布的确认。如果必须再次发送消息,则存储该消息。 QoS2是最安全但最慢的传输模式。
答案 0 :(得分:1)
正如您所确定的,较高的QOS级别描述了客户端(发布者或订阅者)与代理之间的消息传递,而不是端到端的发布者与订阅者的传递。
这是非常慎重的,因为作为发布/订阅协议,无法知道主题可能有多少订阅者。在0和n之间可以有任何数字。发布者和订阅者也可以与不同QOS级别的主题进行交互(发布者可以在QOS 2发布,订阅者可以在QOS 0订阅)。消息也可以作为保留消息发布,这样最后保留的消息将始终传递给新订阅的客户端。
客户端上满足QOS合同的所有存储应由您正在使用的MQTT库处理(在本例中为Paho)
deliveryComplete
回调仅表示发布者已完成将消息发送给代理。此外,doc表示如果邮件已经传递,token.getMessage()
将返回null,这将解释您提到的异常(我必须在此猜测,因为您没有包含异常)。< / p>
如果您的应用程序架构确实要求对消息进行端到端的确认,那么您将需要实现类似于您所描述的内容。但是为了确保它正常工作,您应该在消息的有效负载中包含消息ID,并且确认消息应该包含此消息,并且可能通过某种方式识别哪个订阅者正在回复以确保您知道谁收到了消息。我会使用这样的东西的唯一原因是,如果有时间要求确认消息。如果时间不是相关因素,那么请查看使用持久会话,以确保在发布时断开连接时,如果消息在重新连接时传递给订阅客户端。