написание слушателя TCP с объектом в качестве параметра - PullRequest
0 голосов
/ 28 октября 2011

Я понимаю, как отправить объект через TCP-соединение в C #;Я использую StreamWriter.

Как я могу получить этот объект с другой стороны?

Я пробовал StreamReader, но он не содержит параметр типа object.

Какэто можно сделать?

Ответы [ 3 ]

1 голос
/ 28 октября 2011

IMO лучшее решение - использовать BinaryReader для чтения из потока.Более того, вы должны записать поток, используя класс BinaryWriter.

Если ваш объект не относится к одному из базовых типов, вам необходимо выполнить сериализацию перед отправкой через TCP-соединение.

0 голосов
/ 28 октября 2011

Если вы не хотите или не можете использовать BinaryFormatter , вам придется десериализовать объект yoursekf

Модифицированный пример из msdn для двоичного форматера:

Допустим, у вас есть модель:

[Serializable] //you could also make the class implement ISerializable
class SomeModel
{
    public String Name
    {
        get;
        set;
    }
}

у вас есть NetworkStream:

NetworkStream ns;

Базовый пример того, как вы будете выполнять сериализацию:

void Serialize() 
{
    SomeModel myModel = new SomeModel()
    {
        Name = "mooo"
    };

    // Construct a BinaryFormatter and use it to serialize the data to the stream.
    BinaryFormatter formatter = new BinaryFormatter();
    try 
    {
        formatter.Serialize(ns, myModel);
    }
    catch (SerializationException e) 
    {
        throw e;
    }
}

и что касается десериализации

void Deserialize() 
{
    SomeModel myModel;
    try 
    {
        BinaryFormatter formatter = new BinaryFormatter();

        // Deserialize the object from the stream and 
        // assign the reference to the local variable.
        myModel = (SomeModel) formatter.Deserialize(ns);
    }
    catch (SerializationException e) 
    {
        throw e;
    }
}

Есть одна вещь, о которой ты должен позаботиться. Вы должны знать, когда вы десериализуете, вы не можете просто бросить поток и получить что-то обратно, вы должны знать, что то, что вы собираетесь прочитать, на самом деле является сериализованным SomeModel-классом. Я не знаю, как выглядит ваш код, поэтому я не знаю, является ли это проблемой или нет, и если это то, как ее избежать.

В любом случае, ваш второй выбор - использовать BinaryReader. Вам нужно будет создать экземпляр своего объекта и прочитать данные вручную.

using(BinaryWriter writer =
    new BinaryWriter(ns))
{
    binWriter.Write(myModel.Name);
}

чтение:

 using(BinaryReader reader =
        new BinaryReader(ns))
 {
    try
    {
        SomeModel myModel = new SomeModel();

        myModel.Name = binReader.ReadString();
    }

    // If the end of the stream is reached before reading
    // the four data values, ignore the error and use the
    // default settings for the remaining values.
    catch(EndOfStreamException e)
    {
        Console.WriteLine("{0} caught and ignored. " +
            "Using default values.", e.GetType().Name);
    }
}
0 голосов
/ 28 октября 2011

Я действительно могу порекомендовать использовать ProtoBuf для преобразования ваших объектов в / из байтов, которые вы можете отправить по сети (например, сериализация).Это намного лучше, чем встроенные двоичные сериализаторы (скорость, управление версиями).

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

Ниже приводится вспомогательный класс, который я использовал для сериализации и сетевого взаимодействия после установления соединения:

public class Messenger
{
    private readonly TcpClient client;

    private readonly NetworkStream stream;

    public IPEndPoint RemoteEndPoint { get { return (IPEndPoint) client.Client.RemoteEndPoint; } }

    public Messenger( TcpClient client )
    {
        this.client = client;
        stream = client.GetStream();
    }

    #region Send and Receive
    public TResponse SendReceive<TRequest, TResponse>( TRequest request ) where TRequest : Message where TResponse : Message
    {
        Send( request );
        return Receive<TResponse>();
    }

    public void Send<TRequest>( TRequest request ) where TRequest : Message
    {
        using( var ms = new MemoryStream())
        {
            Serializer.SerializeWithLengthPrefix( ms, request, PrefixStyle.Fixed32 );
            stream.Write( ms.GetBuffer(), 0, (int) ms.Length );
            stream.Flush();
        }
    }

    public TResponse Receive<TResponse>() where TResponse : Message
    {
        try
        {
            return GetMessage<TResponse>();
        }
        catch (Exception ex)
        {
            if (ex is IOException || ex is InvalidOperationException)
            {
                stream.Dispose();
            }
            throw;
        }
    }
    #endregion

    #region Helpers
    private TMessage GetMessage<TMessage>() where TMessage : Message
    {
        int messageLength = BitConverter.ToInt32(GetBytes(stream, 4), 0);
        byte[] data = GetBytes(stream, messageLength);
        using (var ms = new MemoryStream(data))
        {
            return Serializer.Deserialize<TMessage>(ms);
        }
    }

    private static byte[] GetBytes(NetworkStream stream, int length)
    {
        int bytesRequired = length;
        int bytesRead = 0;
        var bytes = new byte[length];
        do
        {
            while( !stream.DataAvailable )
                Thread.Sleep( 100 );                    
            int read = stream.Read(bytes, bytesRead, bytesRequired);
            bytesRequired -= read;
            bytesRead += read;
        }
        while (bytesRequired > 0);
        return bytes;
    }
    #endregion
}

Примечание. Сериализаторкласс из библиотеки ProtoBuf. * ​​1010 *

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...