11

ProtoBuf-Net を使用してコンパクト フレームワークと完全な .Net フレームワーク間でシリアル化/逆シリアル化する際の問題を認識している人はいますか? コンパクト フレームワーク 3.5 でシリアル化する LogData というクラスがあり、サーバー (.Net Framework 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;
  }
4

2 に答える 2

15

簡単なもの:あなたが使う:

var buffer = ms.GetBuffer();

そしてbuffer.Length。これは、特大のパッド入りバッファーを使用していることを意味します。その場合は、を使用する必要があります。ms.Lengthこれにより、実際の長さがわかります。または、ms.ToArray()使用することもできますが、追加のコピーが必要になります。

私のアドバイス:GetBuffer()を使い続けますが、buffer.Lengthバイトではなく、ms.Lengthバイトのみを書き込みます。

これらの余分な誤ったゼロを削除すると、機能することがわかると思います。

于 2012-05-01T18:23:53.497 に答える
0

主な開発者 @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: この素晴らしいライブラリをありがとう!

于 2015-04-03T13:41:09.180 に答える