“源数据中的无效字段:0”错误与ProtoBuf-Net和紧凑框架
本文关键字:ProtoBuf-Net 错误 框架 数据 无效 字段 | 更新日期: 2023-09-27 18:33:01
在使用
ProtoBuf-Net在紧凑框架和完整的.Net框架之间进行序列化/反序列化时,有没有人知道任何问题? 我有一个名为 LogData 的类,我在紧凑框架 3.5 下对其进行序列化,传输到服务器(运行 .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;
}
简单的一个:你使用:
var buffer = ms.GetBuffer();
然后buffer.Length
.这意味着您使用的是超大的填充缓冲区。如果这样做,则需要使用 ms.Length
,它会告诉您实际长度。或者,可以使用ms.ToArray()
,但这涉及额外的副本。
我的建议:继续使用 GetBuffer(),但只写毫秒。长度字节,而不是缓冲区。长度字节。
一旦你删除了这些额外的不正确的零,我希望你会发现它有效。
我意识到主要开发人员已经回答@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:感谢这个伟大的图书馆!