我正在实现客户端 - 服务器应用程序,并正在研究序列化和传输数据的各种方法.我开始使用Xml Serializers,它工作得很好,但是生成数据很慢,并且生成大对象,特别是当它们需要通过网络发送时.所以我开始研究Protobuf和protobuf-net.
我的问题在于protobuf没有发送类型信息.使用Xml Serializers,我能够构建一个包装器,它将在同一个流上发送和接收任何各种(可序列化的)对象,因为序列化为Xml的对象包含对象的类型名称.
ObjectSocket socket = new ObjectSocket();
socket.AddTypeHandler(typeof(string)); // Tells the socket the types
socket.AddTypeHandler(typeof(int)); // of objects we will want
socket.AddTypeHandler(typeof(bool)); // to send and receive.
socket.AddTypeHandler(typeof(Person)); // When it gets data, it looks for
socket.AddTypeHandler(typeof(Address)); // these types in the Xml, then uses
// the appropriate serializer.
socket.Connect(_host, _port);
socket.Send(new Person() { ... });
socket.Send(new Address() { ... });
...
Object o = socket.Read();
Type oType = o.GetType();
if (oType == typeof(Person))
HandlePerson(o as …
Run Code Online (Sandbox Code Playgroud) 我们使用protobuf-net对公共协议基于Google Protocol Buffers的应用程序中的消息进行序列化和反序列化.该库非常出色,涵盖了除此之外的所有要求:我们需要在消息实际序列化之前找出序列化的消息长度(以字节为单位).
这个问题已经在一年半前提出过,根据Marc的说法,唯一的方法就是序列化到MemoryStream并.Length
随后读取属性.在我们的例子中这是不可接受的,因为MemoryStream在幕后分配一个字节缓冲区,我们必须避免这种情况.
来自同一回复的这一行给了我们希望它毕竟是可能的:
如果你澄清用例是什么,我相信我们可以轻松地提供它(如果它还没有).
这是我们的用例.我们有大小在几个字节和两兆字节之间变化的消息.应用程序预先分配用于套接字操作和序列化/反序列化的字节缓冲区,一旦预热阶段结束,就不能创建额外的缓冲区(提示:avoding GC和堆碎片).字节缓冲区基本上是合并的.我们还希望尽可能避免在缓冲区/流之间复制字节.
我们提出了两种可能的策略,它们都需要预先设置邮件大小:
Socket.Send
.我们必须知道下一条消息何时无法放入缓冲区并停止序列化.如果没有消息大小,实现此目的的唯一方法是等待异常发生Serialize
.Socket.Send
.为了从池中检出具有适当大小的字节缓冲区,我们需要知道序列化消息有多少字节.因为协议已经定义(我们不能改变它)并且要求消息长度前缀为Varint32,所以我们不能使用SerializeWithLengthPrefix
方法.
那么是否可以添加一种估计消息大小而无需序列化到流中的方法?如果它不适合图书馆的当前功能集和路线图,但是可行,我们有兴趣自己扩展图书馆.我们也在寻找替代方法,如果有的话.
我是协议缓冲区的新手,我正在为VS2010使用protobuf-net.从我在这里阅读协议缓冲区中的字典,似乎protobuf不能将具有对象类型的字典序列化为值.但在他的网站上我读到了这个:
关于类型的说明
支持的:
自定义类:标记为数据契约具有Silverlight的无参数构造函数:公共许多常见原语等单维数组:T [] List/IList Dictionary/IDictionary任何实现IEnumerable并具有Add(T)方法的类型代码假定类型在选定成员周围是可变的.因此,不支持自定义结构,因为它们应该是不可变的.
这似乎得到了支持.
我可以像这样成功编译一个对象列表:
message ValuesObject {
optional int32 SomeVal = 1;
repeated SomeClass ListOfSomeClassTypes = 2;
}
Run Code Online (Sandbox Code Playgroud)
这适用于List<SomeClass>
.为什么我不能使用protobuf-net序列化Dictionary<int, SomeClass>
?该序列化的消息是什么样的Dictionary<int, SomeClass>
?
我们在.NET中有一些(很多)类.我们使用protobuf-net来标记它们,并通过谷歌原始库为C++代码端生成.proto包装器.
所以我有一条消息(C++ DebugString()在一些EventBase类上(在.NET中EventCharacterMoved
继承,EventBase
而在C++中我只是写入可选属性)):
UserId: -2792
EventCharacterMoved {
Coordinates {
Position {
X: 196.41913
Y: 130
Z: 213
}
Rotation {
X: 207
Y: 130
Z: 213
}
}
OldCoordinates {
Position {
X: 196.41913
Y: 130
Z: 213
}
Rotation {
X: 207
Y: 130
Z: 213
}
}
}
Run Code Online (Sandbox Code Playgroud)
(来自这样的.proto文件)
message Coordinates {
optional TreeFloat Position = 1;
optional TreeFloat Rotation = 2;
}
message EventBase {
optional int32 UserId = …
Run Code Online (Sandbox Code Playgroud) 我有一个基于.NET Standard 1.4的Xamarin.Forms应用程序,它使用protobuf-net在数据库中存储对象,稍后将发送到WCF服务.
在Android和UWP上"托管"一切正常但是 - 在搜索了无法再访问的存储库,文章和博客文章之后,以及在尝试使预编译工具工作之后,但是失败了 - 我有一个简单的(可能)问题:如何让protobuf-net在UWP/.NET Native和iOS/Xamarin等"受限"环境中工作?
请观察以下简单程序(基于protobuf-net项目v1 wiki的示例):
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using ProtoBuf;
namespace HelloProtoBuf
{
[ProtoContract]
class Person
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string Name { get; set; }
[ProtoMember(3)]
public Address Address { get; set; }
}
[ProtoContract]
class Address
{
[ProtoMember(1)]
public string Line1 { get; set; }
[ProtoMember(2)]
public string Line2 { get; set; }
}
class Program
{
static void Main(string[] args)
{
var person = new Person
{
Id = 12345, …
Run Code Online (Sandbox Code Playgroud) 我正在使用协议缓冲区序列化序列化大型数据集.当我的数据集包含400000个大小约为1 GB的自定义对象时,序列化将在3~4秒内返回.但是当我的数据集包含大约1.2 GB的450000个组合大小的对象时,序列化调用永远不会返回并且CPU会不断消耗.
我正在使用Protocol Buffers的.NET端口.
protobuf-net实现的一个限制是它同步调用底层流.通过不提供异步API,例如BeginSerialize/EndSerialize或TPL等价物,我们被迫绑定一个等待同步流I/O的线程.
有没有计划在protobuf-net中提供异步方法,或者有任何创造性的方法来解决这个问题?
首先,这不是IEnumerable <T>的副本作为WCF方法的返回类型,我想我明白WCF架构只允许传输可以填充到消息中的具体类型.
其次,我们的设置不是一般服务,而是通过C#+ WCF + NetTcpBinding + Protobuf(仅)连接一组专有应用程序,因此我们可能有更多空间来处理某些需要更具约束力中性的技巧.
第三,提出不同的RPC或消息框架既不是我的地方,也不是这个问题.
出于这个问题的目的,"IEnumerable语义"是:
List
或相似.foreach
并完成它.在本地程序集中,C#接口看起来像这样:
interface IStuffProvider {
IEnumerable<Stuff> GetItems(); // may open large file or access database
}
Run Code Online (Sandbox Code Playgroud)
您无法将其直接映射到WCF服务.可能达到相同效果的东西可能如下所示:
[ServiceContract(SessionMode = SessionMode.Required)]
interface IStuffService {
[OperationContract]
void Reset(); // may open large file or access database
[OperationContract]
List<Stuff> GetNext(); // return next batch of items (empty list if no more available)
} …
Run Code Online (Sandbox Code Playgroud) 我有一个小单元测试来测试循环依赖.
我的目标如下:
[ProtoContract]
public class Node
{
[ProtoMember(1)]
public String Name { get; set; }
[ProtoMember(2,AsReference = true)]
public List<Node> Childs { get; set; }
public Node()
{
Childs = new List<Node>();
}
}
Run Code Online (Sandbox Code Playgroud)
以下服务:
[ServiceContract]
public interface INodeService : IService
{
[OperationContract]
Task<Node> GetCyclicNodes();
}
public class NodeService : Service, INodeService
{
public async Task<int> Add(int a, int b)
{
return a + b;
}
public async Task<Node> GetCyclicNodes()
{
Node nodeA = new Node() {Name = "Node A"}; …
Run Code Online (Sandbox Code Playgroud)