EndReceive
вполне может получить 0, если поток закрыт и все данные были использованы.Однако для большинства других целей в потоке нет логического разрыва - и даже NetworkStream.DataAvailable
говорит только о том, что доступно на клиенте , а не о том, что было отправлено сервером .Следовательно: если вы отправляете несколько сообщений / etc в одном и том же потоке, обычно необходимо или ставить перед каждым блоком число ожидаемых байтов, или , чтобы использовать некоторую последовательность разделителей, которая быобычно не ожидается в середине контента.Первое часто проще, если содержимое может быть произвольным двоичным содержимым (т. Е. Сложно предсказать последовательность, которая не ожидается), но второе позволяет выполнять потоковую передачу без , заранее зная длины (полезно, еслиВы вычисляете контент на лету, так как в противном случае вам может понадобиться буферизовать контент сначала , чтобы узнать длину (или выполнить пробный прогон без данных).
Также обратите вниманиечто Read
не гарантирует возврата всех доступных данных - было бы вполне законно отправить "HELLO"
, а Read
вернуло бы только 1 (H
). Следовательно, вы должны ожидать объединения нескольких Read
вызовы в одно сообщение (опять же, с использованием префикса длины или ожидаемой последовательности разделителя).
В этом сценарии у меня будет соблазн отправить HELLO\0
(где \0
- ноль-byte). Тогда я бы потреблял через Read
, пока или не вернет <=0
, или a \0
. В случае \0
все, что буферизовано дотерминатор репрпосылает одно сообщение;что-нибудь после разделитель должен быть сохранен и обработан как часть следующего сообщения или сообщений.В качестве тестового примера представьте, что вы получите Read
return 13 с последовательностью a\0b\0cde\0f\0\0\0g
, которая должна "a"
, "b"
, "cde"
, "f"
, ""
, ""
, "g"
(отмечая, что g
не должен обрабатываться - он может быть частью более длинных последовательностей, которые еще не получены - буферизировать до получения \0
).