Как определить, что начался новый пакет и закончился предыдущий?
Протокол TCP считает, что данные идут непрерывным потоком; всё, что не пришло, переспросили, всё, что пришло вне очереди, поставили на место.
Единственный способ — наладить в этом потоке данных искусственные границы пакета. Например:
opcode : word
packetLength : dword
data : byte[packetLength]
В .net есть такие штуки как BinaryReader и BinaryWriter. Если отправить во writer строку на одном конце, то на другом конце reader будет ждать, пока не считает всю строку целиком. Если будет несколько строк, то они считаются последовательно.