Wie kann ich senden mehrere Typen von Objekten über Protobuf?

Ich bin Implementierung einer client-server-Anwendung, und bin auf der Suche in verschiedener Weise zu serialisieren und übertragen der Daten. Ich begann die Arbeit mit Xml-Serialisierungsprogramme, das klappte ziemlich gut, aber Daten generieren, langsam, und machen große Objekte, vor allem, wenn Sie benötigen, um das senden über das Netz. Also suchte ich in Protobuf, und protobuf-net.

Mein problem liegt in der Tatsache, dass protobuf nicht gesendet Art Informationen mit sich. Mit Xml-Serialisierungsprogramme, ich war in der Lage zu bauen ein wrapper, der würde senden und empfangen verschiedene (serializable) - Objekt über den gleichen stream, da Objekt in Xml serialisiert enthalten, die den Typnamen des Objekts.

ObjectSocket socket = new ObjectSocket();
socket.AddTypeHandler(typeof(string));  //Tells the socket the types
socket.AddTypeHandler(typeof(int));     //of objects we will want
socket.AddTypeHandler(typeof(bool));    //to send and receive.
socket.AddTypeHandler(typeof(Person));  //When it gets data, it looks for
socket.AddTypeHandler(typeof(Address)); //these types in the Xml, then uses
                                        //the appropriate serializer.

socket.Connect(_host, _port);
socket.Send(new Person() { ... });
socket.Send(new Address() { ... });
...
Object o = socket.Read();
Type oType = o.GetType();

if (oType == typeof(Person))
    HandlePerson(o as Person);
else if (oType == typeof(Address))
    HandleAddress(o as Address);
...

Habe ich mir überlegt, ein paar Lösungen zu diesem, einschließlich der Erstellung einer master - "Staat" - Typ-Klasse, die ist die einzige Art von Objekt gesendet über mein socket. Dieser bewegt sich Weg von der Funktionalität, die ich gearbeitet habe, mit Xml-Serialisierungsprogramme, obwohl, so würde ich mag, um zu vermeiden, dass Richtung.

Die zweite option wäre, um wrap-protobuf-Objekte in eine Art von wrapper definiert, die den Typ des Objekts. (Dieser wrapper würden auch Daten enthalten, wie z.B. Paket-ID, und das Ziel.) Es scheint albern zu verwenden protobuf-net die Serialisierung eines Objekts, dann kleben Sie, dass Strom zwischen den Xml-tags, aber ich hab mir überlegt es. Gibt es eine einfache Möglichkeit um diese Funktionalität out-of-protobuf oder protobuf-net?


Habe ich eine Dritte Lösung, und die es gepostet unten, aber wenn Sie ein besseres haben, poste es bitte auch!


Informationen auf Feld-bounds-Fehler (mit System.String):

Hashing:

protected static int ComputeTypeField(Type type) //System.String
{
    byte[] data = ASCIIEncoding.ASCII.GetBytes(type.FullName);
    MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
    return Math.Abs(BitConverter.ToInt32(md5.ComputeHash(data), 0));
}

Serialisierung:

using (MemoryStream stream = new MemoryStream())
{
    Serializer.NonGeneric.SerializeWithLengthPrefix
        (stream, o, PrefixStyle.Base128, field);  //field = 600542181
    byte[] data = stream.ToArray();
    _pipe.Write(data, 0, data.Length);
}

Deserializaion:

using (MemoryStream stream = new MemoryStream(_buffer.Peek()))
{
    lock (_mapLock)
    {
        success = Serializer.NonGeneric.TryDeserializeWithLengthPrefix
            (stream, PrefixStyle.Base128, field => _mappings[field], out o);
    }
    if (success)
        _buffer.Clear((int)stream.Position);
    else
    {
        int len;
        if (Serializer.TryReadLengthPrefix(stream, PrefixStyle.Base128, out len))
            _buffer.Clear(len);
    }
}

field => _mappings[field] wirft einen KeyNotFoundException bei der Suche nach 63671269.

Wenn ich ersetzen ToInt32 mit ToInt16 im hash-Funktion, die das Feld Wert eingestellt ist 29723 und es funktioniert. Es funktioniert auch, wenn ich explizit definieren System.String's Feld zu 1. Explizit definieren das Feld 600542181 hat die gleiche Wirkung wie die Verwendung der hash-Funktion zu definieren. Den Wert der Zeichenfolge serialisiert wird, ändert nicht das Ergebnis.

InformationsquelleAutor dlras2 | 2010-06-15
Schreibe einen Kommentar