Шаблон для общей структуры коммуникации (обработка и раскрытие полученных данных) - PullRequest
1 голос
/ 21 апреля 2011

В настоящее время я занимаюсь разработкой основанной на сокетах реализации универсальной коммуникационной "среды", которая работает между C # и Android.

Построить сервер и клиент достаточно просто.Ничего особо сложного в этом нет.

На данный момент реализация содержит 2 основных компонента.

AndroidTcpListener (класс сокета tcp, который обрабатывает связь)
AndroidTcpServer (класс, который создаетэкземпляр TcpListener и обрабатывает DataReceived (из TcpListener) при получении данных)

Данные передаются между клиентом и сервером с использованием стандартного сериализатора XML (я могу перейти в JSON в какой-то момент, но дляВ настоящее время я остановился на XML)

Мне кажется, что я застрял на том, как обрабатывать и раскрывать полученные данные.

Я пытался использовать дженерики, но неважно, как яструктурировать его, кажется, что в конце концов мне приходится создавать AndroidTcpServer<T>, который затем ограничивает меня одним типом данных.

Я попытался создать класс CustomActivator как таковой

class CustomActivator<T> where T : Serialization.ITcpSerializable<T>
{
    public CustomActivator(String xmlTypeName, Byte[] data) 
    {
        this.XmlTypeName = xmlTypeName;
        this.Data = data;
    }

    public String XmlTypeName { get; set; }
    public Byte[] Data { get; set; }

    public T Activate()
    {
        T res =  Activator.CreateInstance<T>();
        using (MemoryStream stream = new MemoryStream(this.Data))
        {
            return res.Deserialize(XElement.Load(stream));               
        }
    }
}

Но опять же, кажется, это ограничивает меня в реализации AndroidTcpServer<T>

Я пытался создать AndroidКласс TcpEvent, который структурирован как таковой

public class AndroidTcpEvent<T>
{
    public AndroidTcpEvent() { }
    public AndroidTcpEvent(String eventName, T data)
    {
        this.EventName = eventName;
        this.Data = data;
    }

    public String EventName { get; set; }
    public T Data { get; set; }
}

Но XMLSerializer, похоже, отказывается хотеть сериализовать его (я думаю, я мог бы реализовать свой собственный сериализатор, но это далеко не тривиально и на самом деле не решает, как я буду выставлятьданные)

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

Так что в основном на этом этапе у меня есть (Внутри класса AndroidTcpServer метод как таковой * 1032)*

private void DataReceived(Object sender, TcpServerMessageReceivedEventArgs e)
{
    //e.Data = Byte[] of XML serialized data of the message sent (Semantics are unimportant)
}

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

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

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

1 Ответ

1 голос
/ 21 апреля 2011

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

Затем вы можете прикрепить свой пользовательский активатор к этому событию, например, так:

class CustomActivator<T> where T : Serialization.ITcpSerializable<T>
{
    public void ListenTo(AndroidTcpServer server)
    {
         server.TcpServerMessageReceived += DataReceived;
    }

    private void DataReceived(object sender, TcpServerMessageReceivedEventArgs e)
    {
        T res =  Activator.CreateInstance<T>();
        using (MemoryStream stream = new MemoryStream(e.Data))
        {
            OnObjectReceived(res.Deserialize(XElement.Load(stream));               
        }
    }

    protected void OnObjectReceived(T obj)
    {
        var handler = ObjectReceived;
        if (handler != null)
        {
            OnObjectReceived(this, new ObjectReceivedEventArgs(obj));
        }
    }
}

I 'Я не уверен насчет типов объектов, которые вы отправляете по проводам.Если вы можете определить тип, содержащийся в сериализованном xml, прежде чем вам действительно потребуется десериализовать весь объект, тогда вы можете изменить CustomActivator так, чтобы он проверял тип и игнорировал его, если он не является его собственным T (надеюсь,это имеет смысл) и вы прикрепляете активаторы для каждого типа, который вы можете получить (возможно, вы можете использовать отражение, чтобы присоединить все типы, реализующие интерфейс ISerializable автоматически).

Обновление : Если вы можетеугадав тип из входящих данных, вы можете сделать что-то вроде этого:

class GenericActivator
{
    public void ListenTo(AndroidTcpServer server)
    {
         server.TcpServerMessageReceived += DataReceived;
    }

    private void DataReceived(object sender, TcpServerMessageReceivedEventArgs e)
    {
        var t = Type.GetType(GuessTypeName(e.Data));

        var res =  Activator.CreateInstance(t) as typeof(ITcpSerializable<>).MakeGenericType(t);
        using (MemoryStream stream = new MemoryStream(e.Data))
        {
            OnObjectReceived(res.Deserialize(XElement.Load(stream));               
        }
    }

    protected void OnObjectReceived(object obj)
    {
        var handler = ObjectReceived;
        if (handler != null)
        {
            OnObjectReceived(this, new ObjectReceivedEventArgs(obj));
        }
    }
}

Вы также можете добавить реестр типов в GenericActivator, где вы можете зарегистрировать прослушиватели для каждого типа, например так:

class GenericActivator
{
     private Dictionary<Type, List<Action<object>> _TypeListeners;

     public void Register<T>(Action<object> objectReceived)
     {
         List<Action<object>> listeners;
         if (!_TypeListeners.TryGet(typeof(T), out listeners)
         {
             listeners = new List<Action<object>>();
         }
         listeners.Add(objectReceived);
     }
}

И тогда только вызывайте слушателей для полученного типа.Предполагается, что GuessTypeName работает надежно.

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