TCP - это протокол stream , а не протокол packet . абсолютно не гарантируется , что вы собираетесь получать данные в тех же точных фрагментах, в которых они были отправлены - все, что гарантировано, это то, что вы получите байты в правильном порядке (или ошибка, или тайм-аут и т. д.). Вы можете получить каждый байт отдельно или 14 сообщений одновременно. Или что-то промежуточное, включая половину сообщения за один прием, а другую половину - за следующий. В случае Unicode (и т. Д.) Это также означает, что один символ может быть разделен на несколько приемов.
Любой протокол мульти-сообщений, основанный на TCP, должен включать в себя какое-то обрамление , то есть какой-то способ узнать, где начинается и заканчивается каждое отдельное сообщение. Поскольку вы используете текстовый протокол, наиболее распространенным вариантом является разделение логических сообщений с помощью CR, LF или CR + LF, а затем ваша задача - буферизовать данные до тех пор, пока у вас не появится полное сообщение - путем поиска конец строки. Для полноты: в случае бинарных протоколов обычно используется полезная нагрузка с префиксом длины с каким-то заголовком, который указывает объем данных в полезной нагрузке, тогда вам просто нужно проанализировать заголовок, определить длину и создать буфер до есть столько данных.
В простых приложениях с текстовым протоколом и без проблем с масштабируемостью может быть возможно использовать StreamReader
(поверх NetworkStream
), чтобы выполнить эту часть за вас, а затем просто использовать ReadLine
или ReadLineAsync
. Обратите внимание, однако, что это было бы плохой идеей на «реальных» серверах (особенно ReadLine
) - вы не хотите, чтобы вредоносный или просто глючный клиент блокировал поток навсегда только потому, что он отправил несколько символов без конец строки , а потом больше ничего не отправлял ... никогда. Конечно, на серьезном сервере вы бы не использовали поток для каждого клиента в любом случае .