2013-12-05 7 views
2

В настоящее время я разрабатываю сетевую оболочку на C#, используя привязку clrmq для ZeroMQ.Сериализация и десериализация по clrmq

Моя проблема в том, что я пытаюсь думать о способе десериализации и сериализации прозрачно; то есть сетевая оболочка может передавать любой объект в виде байтов без знания или ухода за его типом и может десериализоваться на правильный тип на другом конце.

У меня есть класс heirachy следующего

public interface ITransmission 
{ 
    Type Type { get; } 
} 

public abstract class Transmission<T> : ITransmission 
{ 
    public Type Type { get { return typeof(T); } } 
} 

Идея заключается в том, чтобы сериализовать объекты, которые осуществили тип передачи, передачи их через clrmq как байты и десериализация их на другом конце

Моих идеальное решение будет

  1. Быть способным сериализовать объекты любого типа без украшения атрибута или минимального атрибута предпочтительно формат байтового массива (отсюда идея выше, используя объект передачи)
  2. Уметь десериализации принятого формата байтового массива в машинописном объект

Что люди в настоящее время использует или делает, чтобы решить вопрос о сериализации и десериализацию прозрачно? Скорость будет фактором в какой-то момент, но в это время я просто пытаюсь выяснить, какие варианты.

Является ли подразумеваемое ограничение здесь, что сетевые библиотеки должны иметь ссылки на все сборки, содержащие типы, которые должны быть переданы?

Кроме того, другой вопрос заключается в том, должен ли это быть осуществимым подходом, или должен ли сервер и клиент быть строго типизированным с самого начала?

Спасибо за чтение.

+0

Является ли скорость критическим фактором здесь? В прошлом я делал что-то подобное с отражением. Это было много лет назад, но вкратце, что я сделал, был некоторый код, который бы использовал отражение для итерации по каждому члену в объекте, а затем упаковывал его в массив байтов. Принимающая сторона делала то же самое в обратном порядке. Это было невероятно гибко, и IMO довольно гладкий – dferraro

+0

Hiya, скорость будет фактором в какой-то момент, но сейчас я просто собираю идеи. Насколько быстро/медленно было ваше решение? Могу ли я использовать информацию о типе в интерфейсе, чтобы сделать его быстрее? – Bernard

+0

Это было достаточно быстро для моих потребностей, что было довольно высоким требованием к производительности (на самом деле это была 2D-онлайн-многопользовательская игра) – dferraro

ответ

1

пользователя dferraro является хорошей. Но я думаю, что в эти дни можно сделать много лучше с сериализацией в C#. Я настоятельно рекомендую вам пара ZeroMQ как транспорт с инфраструктурой Google Protobuf для компонента сериализации и обмена сообщениями.

Посмотрите на реализацию .NET Protobuf here. Я не буду вдаваться в подробности о его реализации, поскольку он довольно документирован, и здесь есть много хороших вопросов о StackOverflow.Фактически, автор реализации C# Protobuf - Marc Gravell - часто простаивает на SO и отвечает на любые вопросы с помощью тега protobuf-net.

+0

, который был 6 или 7 лет назад, когда я придумал это;). Я подумал, что это датировано. Я никогда не слышал об этом протобуфе, но это выглядит потрясающе. Спасибо, что поделился – dferraro

1

Я смог сделать это успешно в онлайн-многопользовательской игре с использованием Reflection, которая может удовлетворить ваши потребности в зависимости от ваших требований.

Вот ссылка, которая описывает, как я сделал это: http://www.gamedev.net/topic/436066-please-critique-my-serialization-system-net--reflection/

В двух словах, вот как я сериализовать/Derialized мои данные: я создал класс под названием «GameMessage», который используется отражение для сериализации/десериализации себя. Тогда каждый тип сообщения будет просто наследовать от этого класса и волшебства функции ToByte() и конструктор принимающего байт [] работу для него: решение

public class GameMessage 
    { 

     private static int SortFieldInfo(FieldInfo left, FieldInfo right) 
     { 
      if (left.Equals(right)) 
      { 
       return 0; 
      } 

      if (right.Name == "ID") 
       return 1; 
      else if (right.FieldType.Name == "String") 
       return -1; 
      else 
       return 0; 
     } 
     public GameMessage(){} 
     public GameMessage(byte[] data) 
     { 
      List<byte> bytes = new List<byte>(); 
      List<FieldInfo> info = new List<FieldInfo>(this.GetType().GetFields()); 

      info.Sort(SortFieldInfo); 
      int idx = 0; 

      for (int i = 0; i < info.Count; i++) 
      { 
       if (info[i].FieldType.Name == "String")// is string) 
       { 
        string value; 
        UInt16 size; 

        if (i != info.Count - 1) 
        { 
         size = BitConverter.ToUInt16(data, idx); 
         idx += 2; 

         value = ASCIIEncoding.ASCII.GetString(data, idx, size); 
         idx += size; 
        } 
        else 
        { 
         value = ASCIIEncoding.ASCII.GetString(data, idx, data.Length - idx); 
         idx += data.Length - idx; 
        } 

        info[i].SetValue(this,value); 
       } 
       else 
       { 
        if (info[i].Name != "ID") 
        { 
         Type[] types = new Type[2] { data.GetType(), idx.GetType() }; 
         object[] values = new object[2] { data, idx }; 

         info[i].SetValue(this, typeof(BitConverter).GetMethod("To" + info[i].FieldType.Name, types).Invoke(null, values)); 
         idx += Marshal.SizeOf(info[i].FieldType); 
        } 
        else 
        { 
         idx += sizeof(ID); 
        } 
       } 
      } 

     } 
     public byte[] ToByte() 
     { 
      List<byte> bytes = new List<byte>(); 
      List<FieldInfo> info = new List<FieldInfo>(this.GetType().GetFields()); 
      info.Sort(SortFieldInfo); 

      for(int i=0;i<info.Count;i++) 
      { 
       if (info[i].FieldType.Name == "String") 
       { 
        if (i != info.Count - 1) 
        { 
         bytes.AddRange(BitConverter.GetBytes(((UInt16)((string)info[i].GetValue(this)).Length))); 
        } 

        bytes.AddRange(ASCIIEncoding.ASCII.GetBytes((string)info[i].GetValue(this))); 
       } 
       else 
       { 
        bytes.AddRange((byte[])typeof(BitConverter).GetMethod("GetBytes", new Type[] { info[i].FieldType }).Invoke(null, new object[] { info[i].GetValue(this) })); 
       } 
      } 

      return bytes.ToArray(); 
     } 
    } 
+1

Чрезвычайно тщательный ответ и спасибо за образец кода. Однако я все же посмотрел на protobuf :) – Bernard

Смежные вопросы