Что я обычно делаю, это создаю структуру заголовка, которая отправляется
Header Size (int, 4 bytes)
File Name Offset (int, 4 bytes)
File Name Size (int , 4 bytes)
File Data Offset (int, 4 bytes)
File Data Size (int , 4 bytes)
[ message data here]
и затем этот заголовок читается с использованием BinaryReader или копированием байтов в структуру с использованием Marshal. Таким образом, вы всегда будете знать, какие данные поступают и сколько раз вам нужно вызвать Read ().
Поле размера заголовка также помогает с контролем версий протокола (оставьте структуру такой же, но добавьте ее для последующих клиентов, чтобы обеспечить обратную совместимость). Если вы определяете структуру в C #, обязательно сделайте это так:
[StructLayout LayoutKind.Sequential]
struct MessageHeader
{
public int HeaderSize;
public int FileNameOffset;
public int FileNameSize;
public int FileDataOffset;
public int FileDataSize;
}
Тогда Marshal.PtrToStructure
позволит вам создать экземпляр этой структуры прямо из байта [], который вы читаете из сокета