我在网络客户端/服务器应用程序中使用protobuf-net。每个数据包都使用BZip2Input / Output流进行压缩,以压缩我的消息。这已经好几个星期了,但我最近修改了服务器的对象,并且得到了一个例外,即BZip2Input流不支持搜索(它不支持)。我想这是因为protobuf检测到它可以跳过某些字段,并试图方便地这样做。
有没有办法禁用此行为,并强制protobuf-net通过读取数据跳过字段? (不寻求)。
更新:添加了下面的完整堆栈跟踪。根据您的评论,流必须在其CanSeek回调中有一个错误。你觉得怎么样?
Server First Chance Exception: BZip2InputStream Seek n
ot supported Stack Trace: at ICSharpCode.SharpZipLib.BZip2.BZip2InputStream.S
eek(Int64 offset, SeekOrigin origin)
Server_NewRequestReceived Exception: System.NotSupportedException: BZip2InputStream Seek not supported
at ICSharpCode.SharpZipLib.BZip2.BZip2InputStream.Seek(Int64 offset, origin)
at ProtoBuf.ProtoReader.Seek(Stream source, Int32 count, Byte[] buffer)
at ProtoBuf.ProtoReader.SkipField()
at proto_2(Object, ProtoReader)
at ProtoBuf.Serializers.CompiledSerializer.ProtoBuf.Serializers.IProtoSeriali zer.Read(Object value, ProtoReader source)
at ProtoBuf.Meta.RuntimeTypeModel.Deserialize(Int32 key, Object value, source)
at ProtoBuf.Meta.TypeModel.TryDeserializeAuxiliaryType(ProtoReader reader, format, Int32 tag, Type type, ref Object value, Boolean skipOtherFields, asListItem, Boolean autoCreate, Boolean insideList)
at ProtoBuf.Meta.TypeModel.TryDeserializeList(TypeModel model, ader, DataFormat format, Int32 tag, Type listType, Type itemType, ref Object value)
at ProtoBuf.Meta.TypeModel.TryDeserializeAuxiliaryType(ProtoReader reader, format, Int32 tag, Type type, ref Object value, Boolean skipOtherFields, asListItem, Boolean autoCreate, Boolean insideList)
at ProtoBuf.Meta.TypeModel.DeserializeCore(ProtoReader reader, Type type, value, Boolean noAutoCreate)
at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type, SerializationContext context)
at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type)
at ProtoBuf.Serializer.Deserialize(Stream source)
创建此类以解决SharpZipLib错误。
public class NonSeekableStreamWrapper : Stream
{
public Stream BaseStream { get; private set; }
public NonSeekableStreamWrapper(Stream baseStream)
{
BaseStream = baseStream;
}
public override void Flush()
{
BaseStream.Flush();
}
public override long Seek(long offset, SeekOrigin origin)
{
return BaseStream.Seek(offset, origin);
}
public override void SetLength(long value)
{
BaseStream.SetLength(value);
}
public override int Read(byte[] buffer, int offset, int count)
{
return BaseStream.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
BaseStream.Write(buffer, offset, count);
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override long Length
{
get { return BaseStream.Length; }
}
public override long Position { get; set; }
}
答案 0 :(得分:2)
这很有趣。当发生这种情况时,我会非常对完整的堆栈跟踪感兴趣,因为AFAIK会为此检查正确的API,例如(来自ProtoReader.Seek
)。
if (source.CanSeek)
{
source.Seek(count, SeekOrigin.Current);
// ...
}
else
{
// ... does it the hard way, even if that means a Read loop
}
所以不,它目前没有这个选项,因为它信任流来说实话。当然,它可能只是我的错误,因此请求堆栈跟踪。
如果这是一个真正的“东西”,那么可能会添加这样一种机制。
编辑:是的,这是SharpZipLib中BZip2InputStream.cs
的错误;它有:
/// <summary>
/// Gets a value indicating whether the current stream supports seeking.
/// </summary>
public override bool CanSeek {
get {
return baseStream.CanSeek;
}
}
但它也有:
/// <summary>
/// Set the streams position. This operation is not supported and will throw a NotSupportedException
/// </summary>
/// <param name="offset">A byte offset relative to the <paramref name="origin"/> parameter.</param>
/// <param name="origin">A value of type <see cref="SeekOrigin"/> indicating the reference point used to obtain the new position.</param>
/// <returns>The new position of the stream.</returns>
/// <exception cref="NotSupportedException">Any access</exception>
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException("BZip2InputStream Seek not supported");
}
所以,它可以从不寻求,但它声称如果 base 流可以。
它应该报告false
而不是回显基本流CanSeek
。