Чтение из сетевого потока: фрагментация пакета - PullRequest
1 голос
/ 27 марта 2011

У меня есть сервер, который управляет двумя клиентами через NetworkStream.Read.

Протокол приложения:

ClientMessage [128 байт] → ответ от сервера [128 байт]

Теперь на стороне сервера: возможно ли, что MyTcpClient.GetStream().Read() возвращает только <128 байт, хотя все сообщения на стороне клиента имеют длину ровно 128 байт? </p>

Полагаю, что такое клиентское сообщение достаточно короткое, чтобы поместиться в один пакет на уровне tcp / ip, но может ли быть какая-то фрагментация или случайная, хотя?

Является ли NetworkStream.DataAvailable подходящим атрибутом для защиты от этого?

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

Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 27 марта 2011

Возможно ли, что MyTcpClient.GetStream (). Read () возвращает только <128 байт </p>

Да. Вы не можете предполагать, что ваш вызов Read () вернет 128 байтов.

см. документы :

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

См. эту ссылку о том, как правильно читать из потоков

Вместо этого попробуйте что-то вроде этого: (передать байтовый массив длиной 128)

private static void ReadWholeArray (Stream stream, byte[] data)
    {
        int offset=0;
        int remaining = data.Length;
        while (remaining > 0)
        {
            int read = stream.Read(data, offset, remaining);
            if (read <= 0)
                throw new EndOfStreamException 
                    (String.Format("End of stream reached with {0} bytes left to read", remaining));
            remaining -= read;
            offset += read;
        }
    }
1 голос
/ 27 марта 2011

Краткий ответ:

Абсолютно нет гарантии , что вы получите весь пакет за один Read вызов, даже если пакет был отправлен за один Write вызов,и он меньше, чем сетевой MTU, и даже если вы фактически отправляете / считываете из интерфейса обратной связи.Вы не можете ничего с этим поделать.

Документация для Read четко гласит:

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

То, что вы можете сделать, будет выглядеть так (псевдокод)

While (true) {
    Read from stream
    If bytes read == 0 {
        Socket was closed (buffer should be empty here)
        Break
    }
    Append read data to persistent buffer
    While (buffer.Length >= 128) {
        Extract first 128 bytes from buffer (buffer length now reduced by 128)
        Process message
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...