2

この関数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...

}

オブジェクトラッパーはシリアル化/逆シリアル化に役立ち、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>();

か否か?だから私は何が間違っているのか理解できません...

4

1 に答える 1

1

どうぞ:

ObjectDumpProtoBuf = ms.GetBuffer();

これにより、特大のバッキングバッファーが得られます。これは、メモリコピーを回避したい場合に便利ですが、そのバイトのみを処理するように細心の注意を払う必要がありますms.Length残りはガベージです。特に、そのメモリを使用していないため、すべてゼロになります...そしてゼロは有効なフィールドヘッダーではないため、表示されているエラーが発生します。

これが問題であるかどうかを簡単に確認するには、次のものに置き換えます。

ObjectDumpProtoBuf = ms.ToArray();

これは、バッファからのデータの適切なサイズのコピーです。

それが機能する場合は、オーバーサイズの bufferの部分を表すまたは同様のものを返すように切り替えることができます。すなわちArraySegment<byte>

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

あなたがそれでうまくいく理由は、それ自身の長さBinaryFormatterを知っているからです. BinaryFormatterプロトコル バッファは追加可能な形式であるため、それ自体の長さはわかりません。

于 2012-09-26T12:14:45.023 に答える