【问题标题】:Serializing and Sending a Protocol Buffers Message序列化和发送协议缓冲区消息
【发布时间】:2012-10-31 18:53:18
【问题描述】:

我已经用 c# 编写了这个 protobuf 消息

  • C# 客户端:

        public AddressBook InitializeAdressBook() { 
    
            Person newContact = new Person();
            AddressBook addressBookBuilder = new  AddressBook();
            Person john = new Person();
            john.id=1234;
            john.name="John Doe";
            john.email="jdoe@example.com";
            Person.PhoneNumber nr = new Person.PhoneNumber();
            nr.number="5554321";
            john.phone.Add(nr);
            addressBookBuilder.person.Add(john);
            TextBox.Text += ("Client: Initialisiert? " + addressBookBuilder.ToString()) + "\t" + "\n";
            TextBox.Text += " Erster Person " + addressBookBuilder.person.First().name + "\t" + "\n";
    
            return addressBookBuilder;
        }
    

问题

我正在尝试将 protobuf 消息从 c# 客户端发送到此 java 服务器...

  • Java 服务器

    public ControllerThread(Socket s){
    this.s = s; 
    try {
            AddressBook adb = AddressBook.parseFrom(s.getInputStream());
            System.out.println("Server: Addressbook:" + adb.getPersonCount());
    
        } catch (IOException e) { 
            System.out.println("Server: BufferedReader oder PrintWriter von ThermoClient konnte nicht erstellt werden");
            e.printStackTrace(); } 
        } 
    

    }

问题:

我应该将此消息序列化为字节数组,以便将其发送到 java 服务器... 不幸的是,方法 ProtoBuf.Serializer.Serialize 不返回字节数组。 那么如何将它序列化为字节数组并将其发送到我的 Java 服务器呢?任何帮助表示感谢!

【问题讨论】:

  • 这很大程度上取决于您的服务器提供的通信协议
  • 因此,使用 Builder 将其“序列化”为八位字节流,然后使用 Java 中合适的库对其进行“反序列化”。如果您从 .protobuf 文件创建 Proto 对象,则应该有两种语言的自动绑定。请记住,ProtocolBuffers 是二进制的
  • 那么,“有什么问题?”创建数据。序列化数据。发送到某个地方。从某个地方读它。反序列化数据。使用数据。由于序列化技术已经制定出来,剩下的就是如何发送/发送读取数据,并且实际上与 Pr​​otocolBuffers 没有太大关系(除非使用特定的 PB-server/RPC 实现)。
  • 如何序列化数据?谢谢

标签: c# serialization network-programming protocol-buffers protobuf-net


【解决方案1】:

protobuf-net(又名ProtoBuf.Serializer.Serialize)写入。如果您将套接字用作NetworkStream,则可以直接写入该套接字。如果你真的想要byte[],那么使用MemoryStream

byte[] data;
using(var ms = new MemoryStream()) {
     Serializer.Serialize(ms, obj);
     data = ms.ToArray();
}

【讨论】:

  • 谢谢!那么服务器直接写入流或发送字节数组是否会有所不同?
  • @Kaiser4you 这一点取决于消息的大小和消息的结构;在某些情况下(一个巨大的、仅转发的消息),直接写入流以防止必须在内存中缓冲它可能更有效,但在大多数常规使用中,您不会注意到太大的差异。一个轻微的优化是使用.GetBuffer() 而不是.ToArray()但是你必须only写入ms.Length字节 - 支持-MemoryStream 的缓冲区超大,并且包含您不得写入流的垃圾/零。
  • 您是否有直接写入网络流而不是内存流的代码示例:)?
  • @Sir Serializer.Serialize(theNetworkStream, theObject);。如果您在单个套接字上按顺序发送多个对象:SerializeWithLengthPrefix(反序列化相同;在两者中使用相同的设置)
【解决方案2】:

首先,您最好仔细检查 Java 服务器的协议。正如here protobuf 所述,它不是自定界的。这意味着,如果您有一个 TCP 连接并且正在发送多个 protobuf 消息,则必须有一些其他底层协议来处理帧 - 确定一条消息在哪里结束,而另一条消息从哪里开始。

让我们暂时忽略这个问题。序列化消息的实际代码取决于您使用的 C#/protobuf 库。如果你使用 Jon Skeet 的 protobuf-csharp-port,你可以这样序列化它:

AddressBook book = InitializeAddressBook();
byte[] bookBytes = book.ToByteArray();

bookBytes 是地址簿,序列化为字节数组。然后使用您想要的任何套接字库(例如TcpClient)将数据(bookBytes)发送到 Java 服务器。

我不相信这会奏效,因为我认为您没有告诉我们有关 Java 服务器的详细信息。

【讨论】:

  • 我正在使用 Marc Gravell 的 c# protobuf 库 v2。也许因此我没有方法 book.ToByteArray();是 Jon Skeets 的实现更好吗?我想将多条消息发送到单个流。 Java Sever使用如下socket通信
  • 公共 ControllerThread(Socket s) { this.s = s;尝试 { br = new BufferedReader(new InputStreamReader(s.getInputStream())); } catch (IOException e) { System.out.println("Server: BufferedReader oder PrintWriter von ThermoClient konnte nicht erstellt werden"); e.printStackTrace(); } }
  • 我正在使用 Marc Gravell (code.google.com/p/protobuf-net) 的 c# protobuf 库 v2。也许因此我没有方法 book.ToByteArray();是 Jon Skeets 的实现更好吗?
  • 我不能说哪个更好,因为我从未尝试过 protobuf-net。我碰巧先尝试了 protobuf-csharp-port 并且它有效,所以我坚持使用它。我刚刚扫描了 protobuf-net 的文档,看起来您想要的方法名为 Serializer.Serialize。我也无法真正阅读您上面的 Java 评论。也许您应该编辑您的原始问题并添加足够的 Java 代码,以便我们可以看到它是如何反序列化的。更好的格式...
  • 方法 Serializer.Seiralize 不返回一个字节返回。我应该将此消息序列化为字节数组,以便将其发送到我的服务器...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-15
  • 1970-01-01
  • 1970-01-01
  • 2022-01-20
相关资源
最近更新 更多