在反序列化期间我得到下一个异常:“源数据中的无效字段:0”。如何找出源代码中的原因/错误位置?

时间:2012-09-26 11:54:13

标签: c# .net deserialization protobuf-net

在此函数中,我尝试在客户端反序列化class Simulator

private void OnHandshakeSimulationStart(Peer peer, Message msg, int seq)
    {
        System.Diagnostics.Trace.WriteLine("TRY OnHandshakeSimulationStart id = " + System.Threading.Thread.CurrentThread.ManagedThreadId);
        try
        {
            HandshakeSimulationStart simstart = msg as HandshakeSimulationStart;
            if (simstart == null) OnHandshakeFailed();
            System.Diagnostics.Trace.WriteLine("#1.1 id = " + System.Threading.Thread.CurrentThread.ManagedThreadId);

            //Simulator sim = (Simulator)simstart.SimulationState.GetObject();
            Simulator sim = null;
            System.Diagnostics.Trace.WriteLine("#1.2 id = " + System.Threading.Thread.CurrentThread.ManagedThreadId);

            try
            {
               // sim = (Simulator)simstart.SimulationState.GetObject();
                using (MemoryStream ms = (MemoryStream)simstart.SimulationState.GetObjectWoDeserialize())
                {
                    System.Diagnostics.Trace.WriteLine("#2.1 id = " + System.Threading.Thread.CurrentThread.ManagedThreadId);
                    ms.Seek(0, SeekOrigin.Begin);
                    System.Diagnostics.Trace.WriteLine("#2.2 id = " + System.Threading.Thread.CurrentThread.ManagedThreadId);
                    sim = Serializer.Deserialize<Simulator>(ms); //(Simulator)new BinaryFormatter().Deserialize(ms);
                    System.Diagnostics.Trace.WriteLine("#2.3 id = " + System.Threading.Thread.CurrentThread.ManagedThreadId);
                }
            }
            catch (SerializationException e)
            {
                Console.WriteLine("Failed to deserialize. Reason: " + e.Message);                    
            }

            System.Diagnostics.Trace.WriteLine("#3 id = " + System.Threading.Thread.CurrentThread.ManagedThreadId);
            sim.PostDeserialize();
            System.Diagnostics.Trace.WriteLine("#4 id = " + System.Threading.Thread.CurrentThread.ManagedThreadId);
            lock (this)
            {
                simulator = sim;
                // команды полученные до этого ставим в очередь
                foreach (Commands.Command cmd in CollectedCommandsDuringHandshake)
                    if (cmd.tact >= simulator.tactCounter)
                        simulator.InternalQueue(cmd);
                System.Diagnostics.Trace.WriteLine("#5 id = " + System.Threading.Thread.CurrentThread.ManagedThreadId);
                CollectedCommandsDuringHandshake = null;

                // настраиваем сетевое время
                networkTime = new Network.Timer(simulator.HZ);
                // настраиваем обработчик команд
                simulator.OnAfterCommand.Add(typeof(Commands.Command), new CommandHandler(OnAfterCommand));
                System.Diagnostics.Trace.WriteLine("#6 id = " + System.Threading.Thread.CurrentThread.ManagedThreadId);
                // хендшейк закончен
                OnHandshakeCompleted();
                System.Diagnostics.Trace.WriteLine("#7 id = " + System.Threading.Thread.CurrentThread.ManagedThreadId);
                CurrentReceiveHandler = new Peer.MessageReceivedHandler(OnMessageReceivedInActiveState);
                System.Diagnostics.Trace.WriteLine("#8 id = " + System.Threading.Thread.CurrentThread.ManagedThreadId);
            }
        }
        catch (Exception exception)
        {
            System.Diagnostics.Trace.WriteLine("OnHandshakeSimulationStart ERROR: " + exception.Message + " id = " + +System.Threading.Thread.CurrentThread.ManagedThreadId);                
        }
    }

通过使用DebugView.exe应用程序,我得到:

[26480] Client handshaked: id=0 name=ECDIS[1] version=3.8.1 
[26480] ObjectWrapper(object obj) - ms.Length = 67 id = 10 
[26480] Write(Network.Packet packet) - ObjectDumpProtoBuf.Length = 256 id = 10 
[25404] ObjectWrapper(Network.Packet packet) - len = 256 id = 5 
[25404] TRY OnHandshakeSimulationStart id = 5 
[25404] #1.1 id = 5 
[25404] #1.2 id = 5 
[25404] GetObjectWoDeserialize() id = 5 
[25404] #2.1 id = 5 
[25404] #2.2 id = 5 
[25404] OnHandshakeSimulationStart ERROR: Invalid field in source data: 0 id = 5 

我发现反序列化期间引发的异常class Simulator

namespace Trainer
{
[Serializable]
[ProtoContract]
public class Simulator
{

    [ProtoMember(1)]
    public IDictionary<int, Task> tasks = new Dictionary<int, Task>();

    [ProtoMember(2)]
    public Workplace[] workplaces;

    [ProtoMember(3)]
    public int tactCounter = 0;

    [ProtoMember(4)]
    public int tactLimit = 0;

    [NonSerialized]
    public int sheduleLimit = 0;

    [ProtoMember(5)]
    public int HZ = 100; 

    public int SyncFactor { get { return 1; } } // HZ/8

    public double DT { get { return 1.0 / (double)HZ; } }

    [ProtoMember(6)]
    List<Commands.Command> commandQueue = new List<Commands.Command>();
    //Queue commandQueue = new Queue();

    [NonSerialized]
    public CommandEventTable OnBeforeCommand = new CommandEventTable();

    [NonSerialized]
    public CommandEventTable OnAfterCommand = new CommandEventTable();

    public void PostDeserialize()
    {
        OnBeforeCommand = new CommandEventTable();
        OnAfterCommand = new CommandEventTable();
        foreach (Task t in tasks.Values)
            t.PostDeserialize();
    }

    public Simulator()
    {

    }

//there are also a lot of functions...

}

一个Object包装器有助于序列化/反序列化,并且它可以正常使用binaryformatter,但我将其更改为使用protobuf-net:

namespace Trainer.Network
{
    [Serializable]
    [ProtoContract]
    public class ObjectWrapper : IFile
    {
    //public byte[] ObjectDump;

    [ProtoMember(1)]
    public byte[] ObjectDumpProtoBuf;

    public ObjectWrapper(object obj)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            //for protobuf-net:
            Serializer.Serialize(ms, obj);
            ObjectDumpProtoBuf = ms.GetBuffer();

            //for binaryformatter:
            //new BinaryFormatter().Serialize(ms,obj);
            //ObjectDump = ms.GetBuffer();

            _Guid = Guid.NewGuid();

            System.Diagnostics.Trace.WriteLine("ObjectWrapper(object obj) - ms.Length = " + ms.Length + " id = " + System.Threading.Thread.CurrentThread.ManagedThreadId);
        }
    }

    public ObjectWrapper(Network.Packet packet)
    {
        bool body = packet.ReadBool();
        if (body)
        {
            int len = packet.ReadInt();
            ObjectDumpProtoBuf = (byte[])packet.Read(typeof(byte), len);
            //ObjectDump = (byte[])packet.Read(typeof(byte),len);

            System.Diagnostics.Trace.WriteLine("ObjectWrapper(Network.Packet packet) - len = " + len + " id = " + System.Threading.Thread.CurrentThread.ManagedThreadId);
        }
        else
            _Guid = (Guid)packet.Read(typeof(Guid));

    }

    public void Write(Network.Packet packet)
    {
        System.Diagnostics.Trace.WriteLine("Write(Network.Packet packet) - ObjectDumpProtoBuf.Length = " + ObjectDumpProtoBuf.Length + " id = " + System.Threading.Thread.CurrentThread.ManagedThreadId);
        packet.Write(true);

        //packet.Write((int)ObjectDump.Length);
        //packet.Write(ObjectDump);           
        packet.Write((int)ObjectDumpProtoBuf.Length);
        packet.Write(ObjectDumpProtoBuf);
    }

    public void WriteFileRef(Network.Packet packet)
    {
        packet.Write(false);
        packet.Write(Guid);
    }

    public object GetObject()
    {
        //using (MemoryStream ms = new MemoryStream(ObjectDump))
        using (MemoryStream ms = new MemoryStream(ObjectDumpProtoBuf))
            return new BinaryFormatter().Deserialize(ms);
    }

    public MemoryStream GetObjectWoDeserialize()
    {
        System.Diagnostics.Trace.WriteLine("GetObjectWoDeserialize() id = " + System.Threading.Thread.CurrentThread.ManagedThreadId);
        return new MemoryStream(ObjectDumpProtoBuf);
    }

    #region IFile Members

    [ProtoMember(2)]
    public Guid _Guid = new Guid();
    public Guid Guid { get { return _Guid; } }

    public byte[] Data
    {
        //get { return ObjectDump; } 
        //set { ObjectDump = value;} 
        get { return ObjectDumpProtoBuf; }
        set { ObjectDumpProtoBuf = value; }
    }
    #endregion
}

}

问题:如何确定问题的确切位置?我的意思是“源数据中的无效字段:0”源数据0是什么? 这是一个

   [ProtoMember(1)]
    public IDictionary<int, Task> tasks = new Dictionary<int, Task>();
是不是? 所以我无法理解有什么不对......

1 个答案:

答案 0 :(得分:1)

我们走了:

ObjectDumpProtoBuf = ms.GetBuffer();

它为您提供超大后备缓冲区。如果你想避免内存复制,这很方便,你需要非常小心,只处理ms.Length个字节 - 剩下的就是垃圾。特别是,由于你没有使用那个内存,它将全部为零......并且零不是有效的字段标题,并且会导致你看到的错误。

要快速检查是否存在问题,请将其替换为:

ObjectDumpProtoBuf = ms.ToArray();

这是来自缓冲区的正确大小的数据副本。

如果可以,可能想切换到返回ArraySegment<byte>或类似代表超大缓冲区的部分;即。

new ArraySegment<byte>(ms.GetBuffer(), 0, (int)ms.Length);

BinaryFormatter使用它的原因是BinaryFormatter知道自己的长度。协议缓冲区是一种可附加格式,因此它知道它自己的长度。