Безопасная маркировка начала/конца пакета для передачи TCP/UDP

Я пишу клиент-серверное приложение, которое работает в локальной сети, для обмена данными между клиентом и сервером. Я создал очень простой объект NetworkCommand, который преобразуется в byte[] и отправляется с помощью TCP или UDP.

Проблема заключается в правильной маркировке end-of-packed,

прямо сейчас я использовал byte[] {0, 0, 0} и маркер конца пакета, но, похоже, это повторяется слишком много раз в самом полном пакете.

Итак, как безопасно пометить end-of-packet?

NetworkCommand.cs

using System;
using System.IO;

namespace Cybotech.Common
{
    public enum CommandType
        {
            NeedIP = 1,
            IPData = 2,
        }

    public class NetworkCommand
    {
        public NetworkCommand(CommandType type, byte[] data)
        {
            Command = type;
            Data = data;
        }

        public int Length
        {
            get { return Data.Length; }
        }

        public byte[] Data { get; set; }
        public CommandType Command { get; set; }

        public byte[] ToBytes()
        {
            MemoryStream stream = new MemoryStream();

            //write the command type
            byte[] data = BitConverter.GetBytes((int) Command);
            stream.Write(data, 0, data.Length);

            //append the length of the data
            data = BitConverter.GetBytes(Length);
            stream.Write(data, 0, data.Length);

            //write the data
            stream.Write(Data, 0, Data.Length);

            //end of packer marker
            data = new byte[] {0, 0, 0};
            stream.Write(data, 0, 3);

            data = stream.ToArray();
            stream.Close();
            stream.Dispose();
            return data;

        }

        public static NetworkCommand CreateNetworkCommand(byte[] bytes)
        {
            MemoryStream stream = new MemoryStream(bytes);
            BinaryReader reader = new BinaryReader(stream);

            CommandType type = (CommandType) reader.ReadInt32();
            int length = reader.ReadInt32();
            byte[] data = reader.ReadBytes(length);
            byte[] endMarker = reader.ReadBytes(3);

            NetworkCommand cmd = new NetworkCommand(type, data);
            reader.Close();
            stream.Close();
            stream.Dispose();
            return cmd;

        }

    }
}

person Parimal Raj    schedule 08.06.2013    source источник


Ответы (1)


Одна из стратегий заключается в том, чтобы начать пакет, скажем, с 4-байтового числа, представляющего размер пакета, и следовать за ним соответствующим количеством байтов полезных данных. Тогда вы точно знаете, сколько данных вам нужно прочитать на принимающей стороне.

TCP — надежный протокол, поэтому вам не нужно слишком беспокоиться о синхронизации. С другой стороны, он ориентирован на поток, и, поскольку вы используете пакетный прикладной уровень, вам может быть проще использовать UDP, ориентированный на сообщения.

Если вы используете UDP, вы можете использовать длину 4 байта, за которой следует произвольный «начальный» символ (например, [), затем полезная нагрузка и, наконец, «стоповый» символ (например, ]). Если вы читаете пакет, который не заканчивается стоп-символом, вы можете отбросить его и продолжить отбрасывать данные до следующего стоп-символа. Но тогда вам понадобится способ попросить отправителя повторно передать потерянные данные.

Хороший протокол использует базовые уровни, поэтому вам не нужно будет дублировать их функции.

person Adam Liss    schedule 08.06.2013
comment
в любом случае, я должен отметить начальный заголовок или конечный маркер? - person Parimal Raj; 08.06.2013