致 marc 或任何有 protobuf-net 经验的人:
我有一个架构,其中服务器与客户端保持终身持久连接(通过 TCP)。由于连接层/服务器应该具有较高的正常运行时间,因此它仅对消息进行反序列化并将其传递到应用程序服务器/层。它本身不包含商业逻辑。
clients -> connection layer (deserialization) -> app layer (business logic)
Run Code Online (Sandbox Code Playgroud)
问题是,虽然我现在可以更改业务逻辑,但我无法更改应用程序层和客户端共享的模型,因为连接层依赖于反序列化的模型。
有没有办法让连接层仅将消息部分反序列化到基类,以用于转发/路由目的?
否则,我想我必须在基类中创建一个二进制字段,该字段按原样传递并由应用程序层反序列化。一级序列化,二级反序列化。
编辑:充实
class Message
{
User user;
// not much else in here, potentially routing information
}
class RequestType1: Message
{
// lots of fields
// which are specific to this type of request/reply
}
class RequestType2: Message
{
}
Run Code Online (Sandbox Code Playgroud)
连接层不应该关心特定请求类型的结构。这样我就可以随意更改它们,只要客户端和应用程序层都同意。但目前连接层进行反序列化,因此它确实需要知道模型,任何更改都会迫使我重新启动连接服务器。
我只需要它进行足够的反序列化以进行路由,这意味着“用户信息”+“子类型名称/编号”。
我们使用 JSON.NET 将数据与OnDeserialized属性一起序列化,以便在反序列化后执行自定义代码:
[OnDeserialized]
internal void OnDeserializedMethod(StreamingContext context)
{
...
}
Run Code Online (Sandbox Code Playgroud)
现在我们尝试使用protobuf而不是JSON.NET并且该方法没有执行。还有另一种方法可以实现这种行为吗protobuf.net?
这是一个不起作用的示例:
class Program
{
static void Main(string[] args)
{
RuntimeTypeModel.Default.Add(typeof (Profile), false).Add(1000, "Id").Add(1001, "Text");
var test = new Profile {Id = Guid.NewGuid(), Text = "123"};
using (var memoryStream = new MemoryStream())
{
Serializer.Serialize(memoryStream, test);
memoryStream.Seek(0, SeekOrigin.Begin);
var deserialized = Serializer.Deserialize<Profile>(memoryStream);
Console.WriteLine(deserialized.Text); // should output "changed"
Console.ReadLine();
}
}
}
[ProtoContract]
public class Profile
{
public Guid Id { get; set; …Run Code Online (Sandbox Code Playgroud) 可区分联合类型中的每个联合案例都会获得一个标签号
type Result<'TSuccess,'TFailure> =
| Success of 'TSuccess
| Failure of 'TFailure
let cases = FSharpType.GetUnionCases typedefof<Result<_,_>>
for case in cases do
case.Tag
Run Code Online (Sandbox Code Playgroud)
从查看编译的代码来看,它是由编译器生成的,并且根据情况的顺序是常量。所以成功为 0,失败为 1。
我正在尝试设置 protobuf-net 通过创建自定义类型模型并将成功和失败添加为结果的子类型来序列化可区分的联合。但要使其发挥作用,需要为每个类指定 ,并且该类必须保持不变。我希望能够自动化设置,但需要能够有一个与每种类型相关的数字,并且这种关系永远不会改变。如果标签可以在可区分联合定义中进行硬编码,那么它似乎是完美的。
我正在尝试从使用 protobuf 的程序创建的文件中获取原始 protobuf 消息。我不拥有源程序或任何东西,但我会对 的输出感到满意protoc --decode_raw。不幸的是,这不起作用,因为我收到“无法解析输入”错误。我相信这是因为文件中存在 protobuf 数据的标头。源程序是DOTA2,文件开头是这样的;
50 42 44 45 4d 53 32 00 f0 54 0e 03 f7 bf 0d 03
01 ff ff ff ff 0f 7b 0a 08 50 42 44 45 4d 53 32
00 10 2c 1a 2e 56 61 6c 76 65 20 44 6f 74 61 20
32 20 45 55 20 4e 6f 72 74 68 20 53 65 72 76 65
72 20 28 …Run Code Online (Sandbox Code Playgroud) 我们使用 Golang 和 .NET Core 作为我们的相互通信微服务基础设施。服务中的所有数据都基于我们创建的 Protobuffs 协议。这是我们的 Protobuff 之一的示例:
syntax = "proto3";
package Protos;
option csharp_namespace = "Protos";
option go_package="Protos";
message EventMessage {
string actionType = 1;
string payload = 2;
bool auditIsActive = 3;
}
Run Code Online (Sandbox Code Playgroud)
Golang 运行良好,该服务正在根据需要生成内容并将其发送到 SQS 队列,一旦发生这种情况,.NET Core 服务就会获取数据并尝试对其进行序列化。
以下是 SQS 消息示例的内容:
{"@type":"type.googleapis.com/Protos.EventMessage","actionType":"PushPayload","payload":"<<INTERNAL>>"}
Run Code Online (Sandbox Code Playgroud)
但我们收到一个异常,表明线路类型未定义,如下所述:
Google.Protobuf.InvalidProtocolBufferException: Protocol message contained a tag with an invalid wire type.
at Google.Protobuf.UnknownFieldSet.MergeFieldFrom(CodedInputStream input)
at Google.Protobuf.UnknownFieldSet.MergeFieldFrom(CodedInputStream input)
at Google.Protobuf.UnknownFieldSet.MergeFieldFrom(UnknownFieldSet unknownFields, CodedInputStream input)
at Protos.EventMessage.MergeFrom(CodedInputStream input) in /Users/maordavidzon/projects/github_connector/GithubConnector/GithubConnector/obj/Debug/netcoreapp3.0/EventMessage.cs:line 232
at Google.Protobuf.MessageExtensions.MergeFrom(IMessage message, Byte[] …Run Code Online (Sandbox Code Playgroud) 我们最近比较了使用ProtoBuf.NET或TSV(制表符分隔数据)序列化的相同表格数据(包括单表,六列,描述产品目录)的相应文件大小,两个文件随后用GZip压缩(默认的.NET实现).
令我惊讶的是,压缩的ProtoBuf.NET版本占用了比文本版本更多的空间(多达3倍). 我的宠物理论是ProtoBuf不尊重byte语义,因此不匹配GZip频率压缩树; 因此压缩效率相对较低.
另一种可能性是,ProtoBuf实际上编码了更多的数据(例如,为了便于模式版本控制),因此序列化格式在信息方面不具有严格的可比性.
有谁观察到同样的问题?压缩ProtoBuf甚至值得吗?
我为每个播放器服务器端序列化数据,它的大小约为128kb.我序列化一个[255,255] bool数组,这是映射必须的,我可以使用哪些替代品,因为我听说gzip实际上会增加大小?
我听说过protobuf-net,但它没有记录,互联网上也没有例子.
我正在玩ProtoBuf,试图了解预期的压缩类型.作为一个测试案例,我有一个10,000,000个十字符串的列表,我正在序列化,然后将其拆分为3.9mb块.ProtoBuf似乎做得很糟糕,最终创造了30多个块.以下是我运行的测试结果.
ProtoBuf-Net序列化:30个3.9mb块
BinaryFormatter序列化:12个3.9mb块
具有Deflate流序列化的BinaryFormatter:1个72kb块
我这样叫ProtoBuf:
ProtoBuf.Serializer.Serialize<List<string>>(names);
Run Code Online (Sandbox Code Playgroud)
任何帮助表示赞赏.
我正在使用protobuf-net序列化/反序列化我的模型。
我的模型相当简单,序列化似乎一直都可以,但是如果我在模型中添加特定类型,反序列化似乎会失败。
我在模型中添加“ int”,“ long”或“ DateTime”后,立即收到“算术运算导致溢出”异常。
模型:
[ProtoContract]
public class MyModel
{
[ProtoMember(1)]
public DateTime Time { get; set; }
[ProtoMember(2)]
public List<string> SomeList { get; set; }
[ProtoMember(3)]
public string Key { get; set; }
[ProtoMember(4)]
public string Value { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
当我删除“时间”属性时,它似乎总是可以工作。
例外:
at ProtoBuf.ProtoReader.TryReadUInt64VariantWithoutMoving(UInt64& value) in c:\Dev\protobuf-net\protobuf-net\ProtoReader.cs:line 375
at ProtoBuf.ProtoReader.ReadInt64() in c:\Dev\protobuf-net\protobuf-net\ProtoReader.cs:line 357
at ProtoBuf.BclHelpers.ReadTimeSpanTicks(ProtoReader source) in c:\Dev\protobuf-net\protobuf-net\BclHelpers.cs:line 191
at ProtoBuf.Serializers.DateTimeSerializer.Read(Object value, ProtoReader source) in c:\Dev\protobuf-net\protobuf-net\Serializers\DateTimeSerializer.cs:line 35
at ProtoBuf.Serializers.PropertyDecorator.Read(Object value, ProtoReader source) in …Run Code Online (Sandbox Code Playgroud) protobuff-net中的Deserialize方法将Stream作为参数。在我以前使用FileStream并通过它并使其起作用之前,但是现在我必须使用StreamReader,因为我正在将应用程序移植到Windows应用商店/电话中。我收到以下错误:
error CS1503: Argument 1: cannot convert from 'System.IO.StreamReader' to 'System.IO.Stream'
Run Code Online (Sandbox Code Playgroud)
另外这是一个unity3d项目,我得到的另一个错误是:
error CS4028: 'await' requires that the type 'Windows.Foundation.IAsyncOperation<Windows.Storage.StorageFolder>' have a suitable GetAwaiter method. Are you missing a using directive for 'System'?
Run Code Online (Sandbox Code Playgroud)
这很奇怪,因为我将代码包装在#if NETFX_CORE #endif
了其中,这是我正在使用的包含项:
#if NETFX_CORE
using System.IO;
using System.Threading.Tasks;
using Windows.Storage;
#endif
Run Code Online (Sandbox Code Playgroud) protobuf-net ×10
c# ×4
.net ×2
.net-core ×1
architecture ×1
compression ×1
f# ×1
go ×1
grpc ×1
gzip ×1
protocols ×1