Как правило, вы бы отправили длину в первую очередь. Оба конца должны согласовать, как выглядит длина - например, вы можете использовать фиксированный 4-байтовый префикс длины в двоичном виде:
byte[] data = ...
int len = data.Length;
byte[] prefix = Bitconverter.GetBytes(len);
stream.Write(prefix, 0, prefix.Length); // fixed 4 bytes
stream.Write(data, 0, data.Length);
Очевидно, что вызывающая сторона должна сделать то же самое - то есть прочитать первые 4 байта, чтобы получить длину. Для чтения приемник должен следить за тем, чтобы не читать слишком много данных. Одним из способов является использование ограничивающего потока - например, этот класс можно использовать для получения потока, который не будет читать слишком много.
Если вы не хотите, чтобы накладные расходы всегда отправляли 4 байта, тогда возможны некоторые более интересные кодировки - например, использование msb в качестве блока продолжения.
Для информации, protobuf-net - это двоичный сериализатор, разработанный на основе формата сообщений Google «буфер буферов». Он обрабатывает множество деталей для вас и может быть интересен, если вы не хотите тратить много времени на написание кода сериализации. В проекте QuickStart есть примеры для сокетов, например здесь