如何检查订户是否有效,以接受在MQTT上发布的主题的消息

时间:2019-02-06 03:11:11

标签: java mqtt paho

我是MQTT的新手。

我正在用Java实现MQTT,并且正在使用下面的代码供发布者发布到特定主题,

    public void publish()
        {
            MqttClient myClient = null;
            MqttConnectOptions connOpt;
            try {
                //  Subscription with Brokers
                connOpt = new MqttConnectOptions();
                connOpt.setAutomaticReconnect(true);
                connOpt.setCleanSession(true);//if your not setting cleanSession to false then subscriptions shouldn't be persisted.

                String clientID = UUID.randomUUID().toString().replace("-", "");
                System.out.println("clientID " + clientID);

                myClient = new MqttClient("tcp://192.168.10.500:1883", clientID);
                myClient.connect(connOpt);
                String myTopic = "Device1";
                MqttTopic topic = myClient.getTopic(myTopic);

                int pubQoS = 0;
                MqttMessage message = new MqttMessage("mqttMessage".getBytes());
                message.setQos(pubQoS);
                message.setRetained(false);

                MqttDeliveryToken token = null;
                token = topic.publish(message);
                System.out.println("publish successful with the message :: " + message);
                // Wait until the message has been delivered to the broker
                token.waitForCompletion();
            } catch (MqttException me) {
            } catch (Exception e) {
            }
        }

然后我使用下面的代码以订阅者身份阅读特定主题的已发布消息,

public void subscribe()
{
    try {
        MqttConnectOptions connOpt;

        //  Subscription with mqttBrokerEndPoint
        connOpt = new MqttConnectOptions();
        connOpt.setAutomaticReconnect(true);
        connOpt.setCleanSession(true);//if your not setting cleanSession to false then subscriptions shouldn't be persisted.

        String clientID = UUID.randomUUID().toString().replace("-", "");
        System.out.println("clientID " + clientID);

        MqttSubscriber mqttConnection = new MqttSubscriber();
        myClient = new MqttClient("tcp://192.168.10.500:1883" clientID);
        myClient.setCallback(mqttConnection);
        myClient.connect(connOpt);
        myClient.subscribe("Device1");

    } catch (MqttException e) {
    }
}

@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
    try {
        System.out.println(message);
        boolean isValidClient = true;// Here i need to check if this is the valid subscriber for the message publised on topic "Device1"

        //if(isValidClient) {

            if(message != null) {
                System.out.println("message" + message.toString());
            }

            myClient.unsubscribe("Device1");
            myClient.disconnect();
    //}
  }
    catch(Exception e){}
}

上面的实现按原样工作。

由于我是mqtt的新手,因此对上述实现方式有一些疑问。

1)对于一个特定的流,发布者和订阅者中的客户ID是否都应该相同?

或者在发布者和订阅者中都应该像上面一样有所不同:哪个可以随机生成?

    String clientID = UUID.randomUUID().toString().replace("-", "");

这个随机生成的clientID在订阅和发布时都可以正常工作。

但是,如果我为发布者和订阅者使用相同的客户端并验证订阅者?

我的意思是在subsriber中使用“ clientID” myClient = new MqttClient(mqttBrokerEndPoint, "clientID");,然后在发布者中使用相同的“ clientID” myClient = new MqttClient(mqttBrokerEndPoint, "clientID");

我在mqtt broker控制台(使用Windows版本)中收到以下套接字错误,

    1549414715: Socket error on client 82, disconnecting.
    1549414715: New client connected from 192.168.10.500 as clientID (c1, k60).
    1549414715: No will message specified.
    1549414715: Sending CONNACK to 82 (0, 0)
    1549414716: New connection from 192.168.10.500 on port 1883.
    1549414716: Client 82 already connected, closing old connection.
    1549414716: Socket error on client 82, disconnecting.
    1549414716: New client connected from 192.168.10.500 as clientID (c1, k60).
    1549414716: No will message specified.
    1549414716: Sending CONNACK to 82 (0, 0)
    1549414716: New connection from 192.168.10.500 on port 1883.
    1549414716: Client 82 already connected, closing old connection.
    1549414716: Socket error on client 82, disconnecting.
    1549414716: New client connected from 192.168.10.500 as clientID (c1, k60).
    1549414716: No will message specified.
    1549414716: Sending CONNACK to 82 (0, 0)

上述程序无法正常工作。

我们不能同时为订阅者和发布者使用相同的clientID吗?为什么会导致套接字错误并且程序无法运行?

2)实施时是否必须输入用户名和密码?还是可以建立没有下面两个属性的连接?

            connOpt.setUserName(USERNAME);
            connOpt.setPassword(PASSWORD.toCharArray());

3)是否必须将pubQoS用于发布者?我当前将其用作零“ 0”?

        MqttMessage message = new MqttMessage(mqttMessage.getBytes());
        message.setQos(0);
        message.setRetained(false);

对于发布者,还必须保留属性吗?

4)订阅时以下2个属性是强制性的吗?我在代码中使用以下代码。

        connOpt.setAutomaticReconnect(true);
        connOpt.setCleanSession(true);//if your not setting cleanSession to 

false,则不应保留订阅。

5)另外,一旦从MQTT发布者接收到Message并进入MessageArrived回调,如下所示,如何验证它是否为有效订阅者并继续进行逻辑处理?

@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
    try {
        System.out.println(message);
        boolean isValidClient = true;// Here i need to check if this is the valid subscriber for the message publised on topic "Device1"
        //if valid subscriber only i need to read message publised on the topic "Device1"
        **//if(isValidClient) {**

            if(message != null) {
                System.out.println("message" + message.toString());
            }

            myClient.unsubscribe("Device1");
            myClient.disconnect();
    //}
  }
    catch(Exception e){}

我的意思是哪个MQTT API属性可以检查此消息是否仅为此订阅者发送,并且他可以进一步使用消息到达回调中接收到的消息?

即,可以使用MQTT api的哪个属性来检查接收到的消息是否与当前的PROCESS / STEP相关(在下面的SUbscriber程序中)

此主题是在messageArrived回调中验证订阅者的订阅者和发布者之间唯一的公共属性吗?还是我们还有其他共同属性来检查订阅者和发布者之间的有效合同?

还是我们应该使用clientID来验证订户?但是,如果我为订户和发布者使用相同的clientID,我会得到我在第1点中提到的套接字错误。

如何进一步进行?

1 个答案:

答案 0 :(得分:0)

1)您不能对两个mqtt客户端使用相同的客户端ID。 mqtt的客户端ID必须是唯一的。您可以创建不同的主题来处理不同的操作。您可以参考下面的答案

Two paho.mqtt clients subscribing to the same client localy

2)用户名和密码是可选的。如果您的mqtt服务器配置为使用用户名和密码,则您的客户端还需要将用户名和密码传递给mqtt服务器。请参阅下面的链接以了解代码用法

How can i connect a Java mqtt client with username and password to an emqttd(EMQ) broker?

如果需要高级级别,请确保tls / ssl安全

https://dzone.com/articles/secure-communication-with-tls-and-the-mosquitto-broker

3)QOS-服务质量(QoS)级别是消息的发送方和消息的接收方之间的协议,该协议定义了特定消息的传递保证。有关qos的更多信息,请参见下面的链接

https://www.hivemq.com/blog/mqtt-essentials-part-6-mqtt-quality-of-service-levels/

4)自动重新连接(正确)-如果mqtt服务器在运行期间断开连接,则客户端将尝试重新连接到服务器。

清洁会话(True)-重新连接到mqtt服务器时,将删除与相同客户端ID相关联的所有较旧的会话。

清洁会话(False)-在重新连接到mqtt服务器时,将保留与相同客户端ID相关联的所有较旧的会话。在某些情况下,Mqtt服务器会根据QOS级别保留消息。

5)尝试为多个操作创建多个主题。在消息到达方法中,您可以检查哪个主题消息已经到达。然后,您可以基于此调用不同的方法。以下代码是其中一种方法。您可以找到适合您需求的最佳方法。干杯!!!!!

@Override
public void deliveryComplete(IMqttDeliveryToken token) 
{
    try 
    {
        if(token.getTopics()[0].equals("TOPIC_A"))
        {
            //Do something
        }   
        else if(token.getTopics()[0].equals("TOPIC_B"))
        {
            //Do something
        }
    } 
    catch (Exception e) 
    {
        MQTTLogger.logSevere(e);
    }
}

Json数据格式

第一则消息

{
  "client-name":"client1"
  "data":""
}

第二条消息

{
  "client-name":"client2"
  "data":""
}