我正在尝试让一些基于 Paho 的客户端与 Vert.x MQTT 服务器一起使用。我正在尝试发布到我的接收客户端订阅的测试主题。我无法从客户发布商向客户订阅者发送消息。
使用我在互联网上看到的各种示例,我组装了一个 MQTT 代理。 Vert.x MQTT Broker 代码如下:
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();
}
}
}
订阅者和发布者是本地的,尽管一旦我部署应用程序,它们可以(并且将会)远离代理。我用来发布的基于 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();
}
}
请注意,我正在从代理发布一个硬编码字符串(用于测试目的)(如 doPublish 方法中所示),但应该注意的是,我正在捕获发布者客户端在我的端点处理程序中发布的尝试。不幸的是,虽然我将订阅者和发布者连接到代理没有问题,但由于某种原因,消息没有到达订阅者。我尝试了各种方法,但是虽然发布者客户端实际上发布到代理,但由于某种原因,代理的发布无法将字符串发送到订阅者。
我很确定我在这里遗漏了一些东西,但我无法想象它可能是什么。谁能帮我让它工作???
预先感谢您提供任何帮助或见解。
最佳答案
当 MQTT 服务器接收到来自发布者的消息以便调用 endpoint.publishHandler 向其传递消息时,我在代码中没有看到任何逻辑来获取主题并搜索注册的订阅者(端点)该主题并向他们发送消息。 同时,我没有看到您以某种方式编码保存订阅者端点和订阅主题之间的引用以进行上述研究。 请记住,MQTT 服务器不是代理,它不会为您处理主题订阅客户端列表;您可以在其之上建立一个经纪人,这应该是您想要做的事情?
关于java - 无法从 Vert.x MQTT 服务器接收消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47254464/