2.4.x
mica-mqtt-server
Использование eclipse paho mqtt websocket client для подключения к mica-mqtt server привело к ошибкам.
Анномальная информация:
Причина проблемы:
Допущена ошибка в кодировке заголовка HTTP-сообщения, что не соответствует правилам кодирования HTTP. Клиент eclipse paho mqtt websocket строго проверяет эти правила.
Анализ сообщения:
Ответ от mica-net:
HTTP/1.1 101 Switching Protocols\r\n
server: mica-net\r\n
date: Wed, 19 Feb 2025 08:44:44 GMT\r\n
sec-websocket-protocol: mqtt\r\n
content-length: 0\r\n
upgrade: WebSocket\r\n
connection: Upgrade\r\n
sec-websocket-accept: Ax1fAV7Wxcb+jRIxCGT/nuEzadE=\r\n
\r\n
Нормальный ответ HTTP-сообщения должен содержать пробел после двоеточия в заголовках. Пример (ответ EMQX):
HTTP/1.1 101 Switching Protocols\r\n
connection: Upgrade\r\n
date: Wed, 19 Feb 2025 00:57:41 GMT\r\n
sec-websocket-accept: yLgy5oAwNdroPHjshpG4TL3CMD0=\r\n
sec-websocket-protocol: mqtt\r\n
server: Cowboy\r\n
upgrade: websocket\r\n
\r\n
Альтернативное решение — использование hivemq-mqtt-client websocket:
Добавление зависимостей:
<dependency>
<groupId>com.hivemq</groupId>
<artifactId>hivemq-mqtt-client</artifactId>
<version>1.3.5</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
<version>4.1.101.Final</version>
</dependency>
```**Пример использования:**
```java
import com.hivemq.client.mqtt.*;
import com.hivemq.client.mqtt.datatypes.MqttQos;
import com.hivemq.client.mqtt.mqtt5.*;
import com.hivemq.client.mqtt.mqtt5.message.connect.Mqtt5ConnectBuilder;
import com.hivemq.client.mqtt.mqtt5.message.connect.connack.Mqtt5ConnAck;
import java.util.concurrent.CompletableFuture;
public class MqttWebSocketExample {
``````java
public static void main(String[] args) {
// Создание MQTT клиента
Mqtt5Client client = MqttClient.builder()
.webSocketWithDefaultConfig()
.useMqttVersion5()
.serverHost("127.0.0.1")
.serverPort(8083)
.identifier("java-client-" + System.currentTimeMillis())
.buildAsync();
``````java
// Настройка соединения
Mqtt5ConnectBuilder.Send<CompletableFuture<Mqtt5ConnAck>> connectOptions = client.toAsync()
.connectWith()
.cleanStart(true)
.keepAlive(30);
// Асинхронное подключение
connectOptions.send().whenComplete((connAck, throwable) -> {
if (throwable != null) {
System.err.println("Подключение не удалось: " + throwable.getMessage());
} else {
System.out.println("Успешное подключение к серверу!");
// Подписка на тему
client.toAsync().subscribeWith()
.topicFilter("test/topic")
.qos(MqttQos.AT_LEAST_ONCE)
.callback(publish -> {
System.out.println("Получено сообщение: " + new String(publish.getPayloadAsBytes()));
})
.send();
// Отправка сообщения
client.toAsync().publishWith()
.topic("test/topic")
.payload("Привет от Java!".getBytes())
.qos(MqttQos.AT_LEAST_ONCE)
.send();
}
});
}
}
``` // Сохранение программы в активном состоянии
try {
Thread.sleep(60000); // Сохранение соединения 60 секунд
} catch (InterruptedException e) {
e.printStackTrace();
}
client.toAsync().disconnect();
}
}**HTTP протокол запроса заголовков:**
- Протокол позволяет иметь произвольное количество символов LWS (линейного белого пространства) перед значением поля.
- Рекомендовано использовать один пробел (SP) для поддержания чистоты и согласованности.
- В реальных приложениях нет обязательного требования наличия пробела, но следование рекомендациям является лучшим подходом.
**Заключение:**
Чувствую, что ограничения `paho.mqtt` кажутся незаслуженными, стоит рассмотреть возможность прямой поддержки WebSocket в будущей версии клиента MICA-MQTT.