TCP-сокет - это транспортный уровень, его задача: передавать от отправителя получателю последовательность байт, при этом:
а) байты не терять;
б) доставлять эти байты именно в том порядке, в котором они были отправлены.
На этом задачи сокета заканчиваются. Т.е. ваш вопрос не имеет отношения к сокетам.
Вопрос о том, сколько надо читать (и ждать), решается не на транспортном, а на прикладном уровне. Т.е. перед вами фактически стоит задача: разработать протокол прикладного уровня - придумать правила, чего и сколько должна отправлять и ждать каждая из сторон сетевого взаимодействия.
Один из простых способов решения этой задачи - заставить каждую сторону перед отправкой любых данных указывать длину этих данных (например, 4 байта).
Тогда работа получателя в этом случае проста:
1) читаем из сокета 4 байта - длину сообщения;
2) читаем из сокета еще столько байт, сколько указано в длине сообщения.
А на всякие там DataAvailable обращать внимания не стоит, они только вводят в заблуждение. Если нужного нам количества байт еще не поступило - ждем, когда поступит.
Upd.
NetworkStream.DataAvailable всего лишь показывает нам, что данные уже поступили и их можно забрать с помощью Read, однако ничего не говорит о том, сколько еще данных ожидается и уж тем более НЕ сигнализирует о том, что другая сторона закончила передачу данных:
"Use the DataAvailable property to determine if data is ready to be read. If DataAvailable is true, a call to Read returns immediately."
https://docs.microsoft.com/en-us/dotnet/api/system...