Как разобрать битые сообщения, полученные через TCP - PullRequest
0 голосов
/ 03 января 2011

Я отправляю строковое сообщение из моего клиентского приложения в мое серверное приложение, используя сокеты. Я использую DataOutputStream для отправки от клиента и DataInputStream для получения сообщения на моем сервере. Я отправляю одну строку от клиента, но я заметил, что когда она попадает на сервер, она иногда разбивается на несколько сообщений. Как мне справиться с этим или как лучше всего справиться с этим?

Возможно, я могу прочитать каждое полученное сломанное сообщение и проверить каждый символ на наличие разделителя, чтобы узнать, что это конец одного сообщения. Но есть ли лучший способ справиться с этим?

Ответы [ 3 ]

3 голосов
/ 03 января 2011

В TCP нет такой вещи, как "сообщение".Это потоковый протокол.Конечно, на более низких уровнях он передается в отдельных пакетах, но у вас нет возможности управлять им, и то, что вы видите, может отличаться от этих пакетов.Вы просто читаете столько, сколько доступно в приемном буфере в любой конкретный момент.Вы можете воспринимать ваши сообщения как разбитые, но вы также можете столкнуться с ситуацией, когда несколько сообщений приходят как объединенные в один кусок.

Так что при чтении сообщения вы должны использовать какой-либо разделитель, чтобы выяснить, гдеВаше сообщение заканчивается, или используйте заголовок с длиной сообщения.Если вы отправляете простые строки, кодирование их как UTF-8 и завершение их нулевыми байтами должно работать нормально.Очевидно, для более сложных вещей вам понадобится более сложный подход.

0 голосов
/ 03 января 2011

Простой пример отправки длины первым.Примечание: я проверяю длину, когда чтение, поскольку недопустимая длина сообщения может привести к исключению OutOfMemoryException, которое может сбивать с толку / вызывать тревогу.

public static void writeBytes(DataOutput out, byte [] bytes) throws IOException {
    out.writeInt(bytes.length);
    out.write(bytes);
}

public static byte[] readBytes(DataInput in) throws IOException {
    int len = in.readInt();
    if (len < 0 || len > 1 << 24) throw new StreamCorruptedException("Invalid message length "+len);
    byte [] bytes = new byte[len];
    in.readFully(bytes);
    return bytes;
}
0 голосов
/ 03 января 2011

Хоть о префиксе ваших сообщений заголовком? Очень часто отправляют заголовок с длиной и контрольной суммой передачи. Таким образом, вы можете выделить буферы подходящего размера и проверить целостность данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...