开发者

Efficient (Space) Serialization for Network Transfer

I am attempting to write some infrastructure to facilitate updating objects between a server and client(s). This will likely be used in a game, however, I feel that the question is not at all specific to the game (so I have asked it here).

For security and efficiency reasons I would like the server to selectively update object properties. For example, a specific property of an object may only be useful to the client which controls that object, as such the server will only update the 'owner' with this information. Alternatively, some properties may need to be sent to all clients. To implement this I have defined a custom attribute which specifies the manner in which the network should handle the property:

    [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;
        }
    }

Now in an object class I can define properties like so:

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

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

I can then write a simple function which automatically grabs a certain set of properties from an object:

    public byte[] GetBytes(NetworkParameterAttribute.NetworkParameterType type)
    {
        MemoryStream s开发者_开发知识库tream = 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;
    }

A similar function can put the object back together on the receiving side. The issue that I am having is that the serialization is very inefficient in terms of space used. For example, grabbing the ServerToAll properties from a TestObject results in 54 bytes (whereas it could be as little as 4).

So the question: Is there a more efficient way of serializing objects to a byte stream that will work for my intended purpose? Note that I would prefer not to write a lot of serialization related code.

Thank you!


NetworkParameterAttribute should have additional field that denotes the corresponding property as "dirty". Every change to a property should effectively set this flag, and during serialization the flag should be reset. Only dirty properties should actually be serialized.

Additionally, now that the object is only partially serialized, during serialization now you need to provide the information about what properties are being serialized. Maintain one bitvector of dirty properties while you populate the stream, and put this bitvector in the beginning of returned byte array.

EDIT: Instead of having a flag inside an attribute we can have the actual value that was serialized last. The advantage is that we don't need additional code for each property to keep the flag synchronized with the property. During serialization we compare two values and serialize property if the values are not equal.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜