网络传输的高效(空间)序列化

时间:2011-04-15 21:04:42

标签: c# serialization

我正在尝试编写一些基础结构,以便于更新服务器和客户端之间的对象。这可能会在游戏中使用,但是,我觉得这个问题根本不是游戏特有的(所以我在这里问过)。

出于安全性和效率原因,我希望服务器有选择地更新对象属性。例如,对象的特定属性可能仅对控制该对象的客户端有用,因此服务器将仅使用此信息更新“所有者”。或者,可能需要将一些属性发送给所有客户端。为了实现这一点,我已经定义了一个自定义属性,它指定了网络应该处理属性的方式:

    [AttributeUsage(AttributeTargets.Property)]
    public class NetworkParameterAttribute : System.Attribute
    {
        public enum NetworkParameterType
        {
            ServerToOwner,
            ServerToAll,
            ServerToOwnerView,
            OwnerToServer
        }

        private NetworkParameterType type;
        public NetworkParameterType Type
        {
            get
            {
                return type;
            }
        }

        public NetworkParameterAttribute(NetworkParameterType Type)
        {
            this.type = Type;
        }
    }

现在在一个对象类中,我可以像这样定义属性:

    public class TestObject
    {
        [NetworkParameter(NetworkParameterAttribute.NetworkParameterType.ServerToAll)]
        public int ID { get; set; }

        [NetworkParameter(NetworkParameterAttribute.NetworkParameterType.ServerToOwner)]
        public string Name { get; set; }
    }

然后我可以编写一个简单的函数,它自动从对象中获取某组属性:

    public byte[] GetBytes(NetworkParameterAttribute.NetworkParameterType type)
    {
        MemoryStream stream = new MemoryStream();
        BinaryFormatter formatter = new BinaryFormatter();
        foreach (PropertyInfo info in this.GetType().GetProperties())
        {
            foreach (object attribute in info.GetCustomAttributes(true))
            {
                if (attribute is NetworkParameterAttribute &&
                    ((NetworkParameterAttribute)attribute).Type == type)
                {
                    formatter.Serialize(stream, info.GetValue(this, null));
                }
            }
        }
        byte[] buf = new byte[stream.Length];
        Array.Copy(stream.GetBuffer(), buf, stream.Length);
        return buf;
    }

类似的功能可以将对象放回到接收端。我遇到的问题是序列化在使用的空间方面非常低效。例如,从TestObject获取ServerToAll属性会产生54个字节(而它可能只有4个字节)。

所以问题是:是否有更有效的方法将对象序列化为字节流,以实现我的预期目的?请注意,我不想编写大量与序列化相关的代码。

谢谢!

1 个答案:

答案 0 :(得分:1)

NetworkParameterAttribute应该有附加字段,表示相应的属性为“脏”。对属性的每次更改都应该有效地设置此标志,并且在序列化期间应该重置该标志。实际上只应序列化脏属性。

此外,由于对象仅部分序列化,因此在序列化期间,您需要提供有关正在序列化的属性的信息。在填充流时保持一个脏属性的位向量,并将此位向量放在返回的字节数组的开头。

编辑:我们可以拥有最后序列化的实际值,而不是在属性中包含标志。优点是我们不需要为每个属性添加额外的代码来保持标志与属性同步。在序列化期间,如果值不相等,我们比较两个值和序列化属性。