无法从Vert.x MQTT Server接收消息

时间:2017-11-12 21:58:05

标签: java mqtt publish-subscribe vert.x

我正在尝试让一些基于Paho的客户端使用Vert.x MQTT服务器。我正在尝试发布我的接收客户端订阅的测试主题。我很难从客户发布者那里收到消息给我的客户订阅者。

使用我在互联网上看到的一些例子,我已经组建了一个MQTT经纪人。 Vert.x MQTT代理代码的代码如下:

public class MQTTBroker
{      
   public MQTTBroker()
   {
      MqttServerOptions opts = new MqttServerOptions();
      opts.setHost("localhost");
      opts.setPort(1883);

      MqttServer server = MqttServer.create(Vertx.vertx(),opts);

      server.endpointHandler(endpoint -> {
      System.out.println("MQTT client [" + endpoint.clientIdentifier() + "] request to connect, clean session = " + endpoint.isCleanSession());
      endpoint.accept(false);

      if("Test_Send".equals(endpoint.clientIdentifier()))
      {
         doPublish(endpoint);

         handleClientDisconnect(endpoint);
      }
      else
      {
          handleSubscription(endpoint);
          handleUnsubscription(endpoint);
          handleClientDisconnect(endpoint);
      }
     }).listen(ar -> {
      if (ar.succeeded()) {
           System.out.println("MQTT server is listening on port " + ar.result().actualPort());
       } else {
           System.out.println("Error on starting the server");
           ar.cause().printStackTrace();
       }
   });
 }

  protected void handleSubscription(MqttEndpoint endpoint) {
     endpoint.subscribeHandler(subscribe -> {
         List grantedQosLevels = new ArrayList < > ();
         for (MqttTopicSubscription s: subscribe.topicSubscriptions()) {
             System.out.println("Subscription for " + s.topicName() + " with QoS " + s.qualityOfService());
             grantedQosLevels.add(s.qualityOfService());
        }
        endpoint.subscribeAcknowledge(subscribe.messageId(), grantedQosLevels);
    });
}

protected void handleUnsubscription(MqttEndpoint endpoint) {
    endpoint.unsubscribeHandler(unsubscribe -> {
        for (String t: unsubscribe.topics()) {
            System.out.println("Unsubscription for " + t);
        }
        endpoint.unsubscribeAcknowledge(unsubscribe.messageId());
    });
}

protected void publishHandler(MqttEndpoint endpoint) {
     endpoint.publishHandler(message -> {
     endpoint.publishAcknowledge(message.messageId());
     }).publishReleaseHandler(messageId -> {
         endpoint.publishComplete(messageId);
     });
 }

protected void handleClientDisconnect(MqttEndpoint endpoint) {
    endpoint.disconnectHandler(h -> {
        System.out.println("The remote client has closed the connection.");
    });
}

protected void doPublish(MqttEndpoint endpoint) {

   // just as example, publish a message with QoS level 2
   endpoint.publish("Test_Topic",
     Buffer.buffer("Hello from the Vert.x MQTT server"),
     MqttQoS.EXACTLY_ONCE,
     false,
     false);
   publishHandler(endpoint);

   // specifing handlers for handling QoS 1 and 2
   endpoint.publishAcknowledgeHandler(messageId -> {

     System.out.println("Received ack for message = " +  messageId);

   }).publishReceivedHandler(messageId -> {

     endpoint.publishRelease(messageId);

   }).publishCompleteHandler(messageId -> {

     System.out.println("Received ack for message = " +  messageId);
   });
  }
}

我有一个Paho客户端,应该从它订阅的主题接收消息。代码如下:

public class Receiver implements MqttCallback
{

   public Receiver()
   {     
      MqttClient client = null;

      try
      {
         MemoryPersistence persist = new MemoryPersistence(); 
         client = new MqttClient("tcp://localhost:1883",persist);
         client.setCallback(this);
         client.connect();
         client.subscribe("Test_Topic");
         System.out.println("The receiver is initialized.");
      }
      catch(Exception exe)
      {
         exe.printStackTrace();
      }
   }

   @Override
   public void connectionLost(Throwable arg0)
   {
      System.out.println("Connection is lost!");
   }

   @Override
   public void deliveryComplete(IMqttDeliveryToken arg0)
   {
      System.out.println("Delivered!");
   }

    @Override
   public void messageArrived(String theStr, MqttMessage theMsg)
   {
     System.out.println("Message from: "+theStr);

      try
      {
         String str = new String(theMsg.getPayload());
         System.out.println("Message is: "+str); 
      }
      catch(Exception exe)
      {
         exe.printStackTrace();
      }

   }

 }

订阅者和发布者是本地的,但是一旦我部署了我的应用程序,他们就可以(并且将会)远离Broker。我用来发布的基于Paho的代码如下:

public void publish(String theMsg)
{
   MqttClient nwclient = null;

   try
  {
      ServConfigurator serv = ServConfigurator.getInstance();
      MemoryPersistence persist = new MemoryPersistence(); 
      String url = "tcp://localhost:1883";

      nwclient = new MqttClient(url,"Test_Send",persist);

      MqttConnectOptions option = new MqttConnectOptions();
      option.setCleanSession(true);

      nwclient.connect(option);

      MqttMessage message = new MqttMessage(theMsg.getBytes());
      message.setQos(2);
      nwclient.publish("Test_Topic",message);

      nwclient.disconnect();
      nwclient.close();

   }
   catch(Exception exe)
   {
       exe.printStackTrace();
   }
}

请注意,我正在从Broker发布一个硬编码字符串(用于测试目的)(如doPublish方法中所示),但应注意我正在捕获发布者客户端尝试在我的端点处理程序中发布。不幸的是,虽然我将订阅者和发布者连接到代理没有问题,但由于某种原因,消息没有到达订阅者。我尝试了各种各样的东西,但是当发布者客户端实际发布到Broker时,由于某种原因,Broker的发布无法将字符串发送给订阅者。

我很确定我在这里遗漏了一些东西,但我想不出它会是什么。谁能帮助我让这个工作?

提前感谢您提供任何帮助或见解。

1 个答案:

答案 0 :(得分:1)

当MQTT服务器收到来自发布者的消息以便调用endpoint.publishHandler传递消息时,我在代码中看不到任何逻辑来获取主题并搜索注册的订阅者(端点)该主题并向他们发送消息。 同时,我没有看到您以某种方式对用户端点和订阅主题之间的引用进行代码保存以进行上述研究。 请记住,MQTT服务器不是代理,它不会为您提供有关主题的订阅客户端列表;你可以在它上面构建一个你应该做的事情吗?