【问题标题】:"Invalid field in source data: 0" error with ProtoBuf-Net and Compact FrameworkProtoBuf-Net 和 Compact Framework 出现“源数据中的无效字段:0”错误
【发布时间】:2012-05-11 04:51:14
【问题描述】:

在使用 ProtoBuf-Net 在紧凑框架和完整的 .Net 框架之间进行序列化/反序列化时,是否有人知道任何问题?我有一个名为 LogData 的类,我在紧凑框架 3.5 下对其进行序列化,传输到服务器(运行 .Net 框架 4.0),然后进行反序列化。有时它有效,有时它会引发上述错误,我尚未将其缩小到任何特定原因。我已经用不同的值进行了许多测试,但似乎找不到任何押韵或错误发生的原因。我在下面包括我的类(减去各种构造函数)。我曾多次查看任一侧的字节缓冲区,但尚未发现通过线路从一侧发送到另一侧的数据存在差异。

[ProtoContract]
public class LogData
{

  [ProtoContract]
  public enum LogSeverity
  {
     [ProtoEnum(Name = "Information", Value = 0)]
     Information,
     [ProtoEnum(Name = "Warning", Value = 1)]
     Warning,
     [ProtoEnum(Name = "Error", Value = 2)]
     Error,
     [ProtoEnum(Name = "Critical", Value = 3)]
     Critical
  }

  [ProtoMember(1)]
  public string UserID { get; set; }
  [ProtoMember(2)]
  public string ComputerName { get; set; }
  [ProtoMember(3)]
  public ExceptionProxy Exception { get; set; }
  [ProtoMember(4)]
  public LogData.LogSeverity Severity { get; set; }
  [ProtoMember(5)]
  public string Source { get; set; }
  [ProtoMember(6)]
  public string Caption { get; set; }
  [ProtoMember(7)]
  public string Description { get; set; }
  [ProtoMember(8)]
  public DateTime TimeOfOccurrence { get; set; }
  [ProtoMember(9)]
  public Guid SessionID { get; set; }
  [ProtoMember(10)]
  public string MethodName { get; set; }
  [ProtoMember(11)]
  public string OSVersion { get; set; }
  [ProtoMember(12)]
  public string Category { get; set; }
  [ProtoMember(13)]
  public string Location { get; set; }
}

[ProtoContract]
public class ExceptionProxy
{

  [ProtoMember(1)]
  public Type ExceptionType { get; set; }
  [ProtoMember(2)]
  public string Message { get; set; }
  [ProtoMember(3)]
  public string StackTrace { get; set; }
  [ProtoMember(4)]
  public ExceptionProxy InnerException { get; set; }

}

这是我的序列化和发送代码

  private void WriteLogDataToServer(LogData data)
  {
     using (var client = new TcpClient())
     {
        client.Connect(Host, SignalLineServerPort);
        using (var stream = client.GetStream())
        {
           using (var ms = new MemoryStream())
           {
              Serializer.Serialize<LogData>(ms, data);
              var buffer = ms.GetBuffer();
              int position = 0;
              WriteFrameMarkers(stream);
              byte[] frameLengthBuffer = BitConverter.GetBytes(buffer.Length);
              stream.Write(frameLengthBuffer, 0, IntByteSize);
              while (position < buffer.Length)
              {
                 int length = Math.Min(ChunkSize, buffer.Length - position);
                 stream.Write(buffer, position, length);
                 position += ChunkSize;
              }
           }
        }
        client.Close();
     }         
  }

这是读取服务器上数据的代码

  public override LogData ReadData(NetworkStream stream)
  {
     if (stream.DataAvailable)
     {
        try
        {
           const int chunkSize = 250;
           byte[] buffer = new byte[IntByteSize];
           int messageSize = 0;
           int totalBytesRead = 0;
           LogData data;
           using (var ms = new MemoryStream())
           {
              if (!ReadFrameMarkers(stream))
                 return null;
              totalBytesRead = stream.Read(buffer, 0, IntByteSize);
              if (totalBytesRead != IntByteSize)
                 return null;
              messageSize = BitConverter.ToInt32(buffer, 0);
              totalBytesRead = 0;
              while ((totalBytesRead < messageSize))
              {
                 int bufferSize = Math.Min(chunkSize, messageSize - totalBytesRead);
                 buffer = new byte[bufferSize];
                 int bytesRead = stream.Read(buffer, 0, bufferSize);
                 if (bytesRead != 0)
                 {
                    totalBytesRead += bytesRead;
                    ms.Write(buffer, 0, bytesRead);
                 }
              }
              ms.Seek(0, SeekOrigin.Begin);
              data = Serializer.Deserialize<LogData>(ms);
           }
           return data;
        }
        catch (Exception ex)
        {
           Console.WriteLine(string.Format("Error occurred: {0}", ex.Message));
           return null;
        }
     }
     return null;
  }

【问题讨论】:

  • 我可以看到您使用的代码:序列化、发送到线路、从线路读取、反序列化吗?我敢打赌,您不小心在缓冲区中留下了一些 0 填充,而没有限制要读取的长度。
  • 我编辑了帖子以包含序列化和反序列化代码。我省略了处理协商接受连接等的接线代码。如果您需要有关代码的更多详细信息,请告诉我。非常感谢马克。

标签: c# serialization compact-framework deserialization protobuf-net


【解决方案1】:

我意识到主要开发人员 @MarcGravell 已经回答了,但我只是想分享我自己的 0.02 美元,这在这个问题上帮助了我。如果我有一个固定大小的 byte[] 并获得读取的字节数作为回报,我可以在 MemoryStream 声明中指定它并解决问题。此外,由于它适用于 OP,因此在完成阅读之前不要声明 MemoryStream。

byte[] msg = new byte[4096];
int bytesRead = someStreamClass.Read(msg, 0, 4096);
using (MemoryStream ms = new MemoryStream(msg, 0, bytesRead))
{    
    logData = Serializer.Deserialize<LogData>(ms);
}

@MarcGravell:感谢这个伟大的图书馆!

【讨论】:

    【解决方案2】:

    简单的一个:你使用:

    var buffer = ms.GetBuffer();
    

    然后是buffer.Length。这意味着您正在使用超大的填充缓冲区。如果你这样做,你需要使用ms.Length,它会告诉你实际长度。或者,可以使用ms.ToArray(),但这需要额外的副本。

    我的建议:继续使用 GetBuffer(),但只写入 ms.Length 字节,而不是 buffer.Length 字节。

    一旦你删除了这些额外的不正确的零,我希望你会发现它有效。

    【讨论】:

    • 谢谢 Marc,如果你在三州地区,我欠你一些饮料。有趣的是,简单的事情却是最令人沮丧的。
    • @WiredWiz 你想我了!我大约一周前在那里。但不是现在;p
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-07
    • 2022-01-12
    • 2012-04-06
    • 2020-12-09
    • 2010-12-11
    相关资源
    最近更新 更多