C# 具有序列化字节[]成员的Protobuf网络

C# 具有序列化字节[]成员的Protobuf网络,c#,serialization,bytearray,protocol-buffers,protobuf-net,C#,Serialization,Bytearray,Protocol Buffers,Protobuf Net,我有一个传输应用程序,它在发布/订阅服务器中用于在客户端之间中继数据。pub-/sub服务器只需要知道一点关于每个数据段的信息,例如,它需要topicname才能将发布的主题转发给正确的订阅者 为了实现这一点,我想出了一个方案,在这个方案中,一个被修饰为ProtoContract的类包含一个byte[],而byte[]又包含protobuf net序列化数据。这样,服务器只需反序列化它所传递的数据的一小部分(并且不需要知道类型)。我的类型看起来像这样 [ProtoContract] public

我有一个传输应用程序,它在发布/订阅服务器中用于在客户端之间中继数据。pub-/sub服务器只需要知道一点关于每个数据段的信息,例如,它需要topicname才能将发布的主题转发给正确的订阅者

为了实现这一点,我想出了一个方案,在这个方案中,一个被修饰为ProtoContract的类包含一个byte[],而byte[]又包含protobuf net序列化数据。这样,服务器只需反序列化它所传递的数据的一小部分(并且不需要知道类型)。我的类型看起来像这样

[ProtoContract]
public class DataFrame
{
    /// <summary>
    /// Time the data was issued or sampled. In UTC time.
    /// </summary>
    [ProtoMember(1)]
    public DateTime TimeStamp = DateTime.UtcNow;

    /// <summary>
    /// The topic associated with the data
    /// </summary>
    [ProtoMember(2)]
    public string TopicName = string.Empty;

    /// <summary>
    /// Command, can be either Discover, Subscribe, Unsubscribe or Publish
    /// </summary>
    [ProtoMember(3)]
    public string Command = string.Empty;

    /// <summary>
    /// The fully qualified type name of the content
    /// </summary>
    [ProtoMember(4)]
    private string _typeName = string.Empty;

    /// <summary>
    /// Serialized content data (if any)
    /// </summary>
    [ProtoMember(5)]
    private byte[] _content;

    /// <summary>
    /// The fully qualified type name of the content
    /// </summary>
    public string TypeName
    {
        get
        {
            return _typeName;
        }
    }

    /// <summary>
    /// Get the content of this DataFrame
    /// </summary>
    /// <typeparam name="T">Type of the content</typeparam>
    /// <returns>The content</returns>
    public T GetContent<T>()
    {
        MemoryStream ms = new MemoryStream(_content);
        return Serializer.DeserializeWithLengthPrefix<T>(ms, PrefixStyle.Base128);
    }

    /// <summary>
    /// Set the content for this DataFrame
    /// </summary>
    /// <param name="value">The content to set, must be serializable and decorated as a protobuf contract type</param>
    public void SetContent<T>(T value)
    {
        MemoryStream ms = new MemoryStream();
        Serializer.SerializeWithLengthPrefix(ms, value, PrefixStyle.Base128);
        _content = ms.GetBuffer();
        _typeName = value.GetType().AssemblyQualifiedName;
    }

    /// <summary>
    /// Encode the frame to a serialized byte array suitable for tranmission over a network
    /// </summary>
    /// <returns>The encoded byte[]</returns>
    public byte[] Encode()
    {
        DataFrame frame = (DataFrame)this;
        MemoryStream ms = new MemoryStream();
        Serializer.SerializeWithLengthPrefix(ms, frame, PrefixStyle.Base128);
        return ms.GetBuffer();
    }

    /// <summary>
    /// Factory function to create a frame from a byte array that has been received
    /// </summary>
    /// <param name="buffer">The serialized data to decode</param>
    /// <returns>A new dataframe decoded from the byte[]</returns>
    public static DataFrame Decode(byte[] buffer)
    {
        MemoryStream ms = new MemoryStream(buffer);
        DataFrame frame = Serializer.DeserializeWithLengthPrefix<DataFrame>(ms, PrefixStyle.Base128);
        frame._timeStamp = DateTime.SpecifyKind(frame._timeStamp, DateTimeKind.Utc);
        return frame;
    }
}
但这会给我一个protobuf异常,即使内容是字符串

string content = frame.GetContent<string>();
string content=frame.GetContent();

有人对我做错了什么有什么指点吗?

注意:使用
GetBuffer()
是不正确的-您将传输太多的数据(最坏情况下,传输量是内部和外部数组的两倍-因此理论上可能超过2倍);在这种情况下,您应该真正使用
ToArray()
;由于您使用的是带有LengthPrefix的
*,因此不太可能导致失败(只是效率低下)。它引发的实际“protobuf异常”是什么?这很好:(使用
GetBuffer()
,数据是370字节,使用
ToArray()
,数据是118字节,但两者都起作用了)-您能否就我可以做些什么来重现您看到的错误给我更多的上下文?您是否检查过您收到的数据与您认为发送的数据100%相同?哦,顺便说一句:其中90个字节是
字符串的
AssemblyQualifiedName
。。。这可能是一种非常昂贵的指定类型的方法。在检查和重新检查之后,我发现错误实际上是由于重新组装UDP数据包时出现的错误。它只在更大的数据包上露出丑陋的头部,所以我低效的代码触发了这个bug。我根据您的建议更改了代码,改为使用ToArray(),这确实为我节省了大量接线空间。我猜您在构造函数/字段初始化中将字段初始化为
新字节[8]
,对吗?如果是这样,则抑制构造函数(
[ProtoContract(SkipConstructor=true)]
)或抑制追加(
[ProtoMember(n,OverWriteList=true)]
)。protobuf(由google)设计为concat===append。
string content = frame.GetContent<string>();