InputStream не может обработать байты 2016 года - PullRequest
0 голосов
/ 16 марта 2020

Я недавно написал программу на Java, которая автоматически создает зашифрованные соединения и передает данные о них. Теперь у меня проблема в том, что входной поток больше не реагирует, если много данных передается одновременно. (Я пытался передать 2016 байтов сразу)

Но я думаю, что проблема заключается в передаче старшего байта с низкой скоростью.

Сервер:

    public byte[] read() throws IOException {
        byte[] bytes = new byte[2];
        this.inputStream.read(bytes);
        int length = ((bytes[0] & 0xff) << 8) | (bytes[1] & 0xff);
        byte[] buffer = new byte[length];
        this.inputStream.read(buffer);
        return this.encryption.decryptAES(buffer);
    }

Клиент:

    public void write(byte[] message) throws IOException {
        byte[] bytes = new byte[2];
        message = this.encryption.encryptAES(message);
        bytes[1] = (byte) (message.length & 0xFF);
        bytes[0] = (byte) ((message.length >> 8) & 0xFF);
        this.outputStream.write(bytes);
        this.outputStream.write(message);
    }

InputStreams не являются закрытыми или нулевыми. Также не возникло никаких исключений.

Программа зависает при чтении байтов для длины байтового массива на стороне сервера. На стороне клиента байты успешно отправлены.

1 Ответ

2 голосов
/ 16 марта 2020

Вызов read работает, как задумано; вы просто не понимаете, как он устроен (что, правда, немного странно).

Метод read(byteArray) гарантированно считывает не менее 1 байта; он не будет читать ничего, только если возникнет исключение или поток будет закрыт.

Однако не гарантируется заполнение предоставленного байтового массива. Для него вполне нормально читать только 1 байт (spe c говорит, что это нормально, поэтому ваш код должен быть написан, чтобы справиться с этим). Даже если есть еще что отправить.

Итак, сколько байтов вы на самом деле получите? ¯_ (ツ) _ / ¯ Зависит от вашей сетевой карты, ОС, виртуальной машины и фазы луны.

Следовательно, «одиночный» вызов чтения, подобный этому, всегда является ошибкой. Это должно происходить в некотором роде l oop.

К счастью, вам не нужно ничего программировать, если вы не используете довольно старую версию Java; в наши дни тип InputStream имеет метод readNBytes, который гарантирует, что он заполнит весь предоставленный байтовый массив, предоставляя вам меньше байтов, только если происходит исключение или если поток заканчивается до полного Массив байтов заполнен.

Итак, вместо: in.read(buffer), правильный вызов: in.readNBytes(buffer, 0, buffer.length).

Примечание: конструкция read похожа на это, потому что она связана с тем, как I / O фактически работает: я могу дать вам 2016 байтов прямо сейчас; если вы хотите больше, это займет больше времени (еще один обход карты или, возможно, ожидание, пока IP-пакеты проберутся через океан, кто знает, сколько времени это может занять); и часто вы не можете знать, что размер magi c позволяет создать ваш байтовый массив, чтобы вы могли получить максимально быстрый ответ, не делая слишком много запросов к read(), что также будет медленным - таким образом, вы можете не решить эту дилемму, сказав: «Ну, просто дайте небольшой массив байтов, если вы хотите быстрых ответов!». Теперь вы знаете, почему это так:)

...