1

我在网络客户端/服务器应用程序中使用 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; }
    }
4

1 回答 1

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
}

所以不,它目前没有这个选项,因为它相信流说实话。当然,这可能只是我的一个错误,因此请求堆栈跟踪。

如果这是一个真正的“东西”,那么可能有可能添加这样的机制。


编辑:是的,这是BZip2InputStream.csSharpZipLib 中的一个错误;它有:

    /// <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");
    }

因此,它永远无法寻找,但它声称如果基本流可以,它就可以。

它应该报告false而不是回显基本流的CanSeek.

于 2013-06-20T21:03:49.647 回答