Как можно настроить и использовать CQL Native Protocol для работы напрямую?

Мы начали работать с CQL Native Protocol напрямую, и у меня возникла проблема: при чтении и отправке данных в сокет происходит ошибка NegativeArraySizeException. 

Вот фрагмент кода, где это происходит:

```java
private static final String HOST = "127.0.0.1";
private static final int PORT = 9042;

public static void main(String[] args) {
    try (
            Socket socket = new Socket(HOST, PORT);
            DataOutputStream output = new DataOutputStream(socket.getOutputStream());
            DataInputStream input = new DataInputStream(socket.getInputStream())
    ) {
        byte[] connectionRequest = createStartupMessage();
        output.write(connectionRequest);
        output.flush();

        TimeUnit.SECONDS.sleep(3);
        readResponse(input);

        String cqlQuery = "SELECT * FROM system.clients";
        byte[] queryMessage = createQueryMessage(cqlQuery);
        output.write(queryMessage);
        output.flush();

        readResponse(input);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
}

private static byte[] createStartupMessage() {
    String version = "3.0.0"; // Version CQL Protocol
    ByteBuffer buffer = ByteBuffer.allocate(5 + version.length());
    buffer.put((byte) 0x01); // Version
    buffer.put((byte) 0x00); // Flags
    buffer.put((byte) 0x00); // Stream
    buffer.put((byte) 0x00); // Opcode
```

Почему возникает эта ошибка, и как ее можно исправить?
  • 12 ноября 2024 г. 11:03
Ответы на вопрос 1
Ошибка `NegativeArraySizeException` обычно возникает, когда в вашем коде вы пытаетесь создать массив (или выделить место в буфере) с отрицательным размером. Это может произойти, если вы неправильно рассчитываете размер массива, который хотите создать, и передаете отрицательное значение функции выделения памяти.

В вашем случае, чтобы диагностировать и исправить проблему, нужно обратить внимание на две вещи:

1. **Правильность формата сообщений**. Убедитесь, что формат ваших сообщений соответствует спецификации CQL Native Protocol. Например, при подготовке и отправке сообщения для запроса или ответа, вы должны правильно, согласно спецификации, вычислять размеры и использовать байты.

2. **Логика создания сообщения**: Проверьте, как вы создаете сообщения и рассчитываете их размеры. Давайте исправим функцию `createStartupMessage`, чтобы обеспечить корректный расчет размера сообщения.

Вот исправленный код для создания стартового сообщения:

```java
private static byte[] createStartupMessage() {
    String version = "3.0.0"; // Версия CQL Protocol
    // Рассчитаем длину сообщения
    int length = 1 + 1 + 1 + 1 + 2 + version.length(); // 1 (опкод) + 1 (флаги) + 1 (стрим) + 1 (опкод) + 2 (длина версии) + длина версии

    ByteBuffer buffer = ByteBuffer.allocate(length);
    buffer.put((byte) 0x01); // Версия
    buffer.put((byte) 0x00); // Флаги
    buffer.put((byte) 0x00); // Стрим
    buffer.put((byte) 0x00); // Опкод
    buffer.putShort((short) version.length()); // Длина версии
    buffer.put(version.getBytes(StandardCharsets.UTF_8)); // Версия

    return buffer.array();
}
```

Когда вы вызываете `createQueryMessage`, убедитесь, что вы также правильно рассчитываете размер сообщения, которое вы хотите отправить. Например, для запроса, формата и длины сообщения CQL, также должны соответствовать спецификации.

Если ваша последовательность отправки и чтения данных не верна, это также может привести к тому, что вы попытаетесь считать больше байтов, чем доступно, что вызовет ошибки. Убедитесь, что вы правильно обрабатываете все ответы, используя правильные размеры и интервалы ожидания.

### Общие рекомендации:

- Проверяйте WhatsApp коды, версии и спецификации CQL Native Protocol на официальном сайте или документации Apache Cassandra.
- Добавьте тщательную обработку исключений и логирование для диагностики. Это поможет более точно определить, где и почему происходит ошибка.

Если эти изменения не помогут, предоставьте больше информации о том, как вы реализуете `createQueryMessage` и как подобные сообщения размером обрабатываются.
Похожие вопросы