c# - 通用通信框架的模式(处理和公开接收到的数据)

标签 c# xml sockets generics types

目前,我正在开发一个在 C# 和 Android 之间工作的通用通信“框架”的基于套接字的实现。

构建服务器和客户端已经很容易了。这在技术上没什么挑战性。

此时,实现包含 2 个主要组件。

AndroidTcpListener (tcp socket class that handles communication)
AndroidTcpServer (class that creates an instance of the TcpListener and handles the DataReceived (from the TcpListener) when data is received)

Data is sent between the client and the server using the standard XML serializer (I may move to JSON at some point but for the time being I have settled on 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>
我尝试创建一个结构如下的 AndroidTcpEvent 类
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 类内部有一个这样的方法
private void DataReceived(Object sender, TcpServerMessageReceivedEventArgs e)
{
    //e.Data = Byte[] of XML serialized data of the message sent (Semantics are unimportant)
}

总之,我希望获得一些指导,说明人们通常如何处理公开接收的数据并在这样的通用框架中实际创建数据实例,以及是否有任何已知模式可用于解决此问题?

显然,我可以抓取所有这些通用实现的东西,然后为我最终尝试构建的任何应用程序创建一个自定义实现,但我这样做既是一种学习练习,也是我想发布给公众供其他人使用的东西。

希望我已经很清楚了,但是如果有人需要对此进行任何方面的澄清,请告诉我。提前感谢大家的意见。

最佳答案

首先,我认为服务器的责任应该以提高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));
        }
    }
}

我不确定您通过网络发送的对象类型。如果您可以在实际需要反序列化整个对象之前确定序列化 xml 中包含的类型,那么您可以修改 CustomActivator以便它检查类型并在它不是自己的 T 时忽略它(希望这是有道理的)并且您为您可以接收的每种类型附加激活器(也许您可以使用反射来附加所有自动实现 ISerializable 接口(interface)的类型)。

更新 :如果您可以从传入数据中猜出类型,您可以执行以下操作:
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工作可靠。

关于c# - 通用通信框架的模式(处理和公开接收到的数据),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5739843/

相关文章:

C++ 在通过 TCP 发送数据之前发送数据大小

c - 有没有什么方法可以更新并重新启动服务器并将其套接字保持在 "suspended"状态?

c# - 使用 C# 程序自动完成 HTML 表单

c# - WPF 中的圆角文本框

xml - 使用 XSLT 自动生成 XML 模式

android - 通过蓝牙打印机打印时获取 java.io.IOException : read failed, 套接字可能已关闭或超时,请读取 ret: -1

c# - 当鼠标在控件上方时如何消除 ToolStripDropDownButton 上的蓝色焦点

c# - 无法从对话框结果隐式转换为 bool

android - Android 中的圆环按钮

java - 使用 XML 的 Servlet