2

I have written this protobuf message in c#

  • C# client:

        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;
        }
    

Problem

I am trying to send a protobuf message from a c# client to this java server...

  • Java server

    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(); } 
        } 
    

    }

Question:

I should serialize this message to a byte array, so that i can send it to the java server... Unfortunately the method ProtoBuf.Serializer.Serialize dont return a byte array back. So how can i serialize it as a byte array and send it to my Java Server? Any help appreciated thanks!

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
Kaiser4you
  • 83
  • 2
  • 3
  • 10
  • it depend a lot on what communication protocol does your server provide – Vlad Oct 31 '12 at 18:55
  • So, "serialize" to an octect stream using the Builder, and then use a suitable library in Java to "deserialize" it. If you are creating Proto objects from `.protobuf` files, there should be automatic bindings for both languages. Remember, *ProtocolBuffers are binary*. –  Oct 31 '12 at 19:00
  • So then, "what's the problem?" Create the data. Serialize the data. Send to somewhere. Read it from somewhere. De-serialize the data. Use the data. Since the serialization technique is worked out, that leaves how to/send read data and really don't have much to do with ProtocolBuffers (unless using a particular PB-server/RPC implementation). –  Oct 31 '12 at 19:02
  • how can serialize the data? thanks – Kaiser4you Oct 31 '12 at 19:09

2 Answers2

4

protobuf-net (aka ProtoBuf.Serializer.Serialize) writes to streams. If you have the socket available as a NetworkStream, you can just write directly to that. If you really want a byte[], then use MemoryStream:

byte[] data;
using(var ms = new MemoryStream()) {
     Serializer.Serialize(ms, obj);
     data = ms.ToArray();
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • thanks! Does it then make a difference for the sever to write directly to stream or to send a byte array? – Kaiser4you Nov 06 '12 at 16:24
  • 1
    @Kaiser4you that depends a bit on the size of the message, and the structure of the message; in some cases (a huge, forwards-only message) it may be more efficient to write directly to the stream to prevent having to buffer it in memory, but in most regular usage you won't notice much difference. One slight optimisation is to use `.GetBuffer()` instead of `.ToArray()`, ***but*** you must **only** write `ms.Length` bytes of that - the backing-buffer of a `MemoryStream` is *oversized*, and contains garbage / zeros that you *must not* write to the stream. – Marc Gravell Nov 07 '12 at 07:33
  • Do you have a code example of writing direct to the network stream instead of memory stream by any chance :) ? – Sir Nov 21 '17 at 19:42
  • @Sir `Serializer.Serialize(theNetworkStream, theObject);`. If you are sending multiple objects in a sequence on a single socket: `SerializeWithLengthPrefix` (and same for deserialize; use the same settings in both) – Marc Gravell Nov 22 '17 at 06:38
1

First you had better double check the protocol of the Java server. As described here protobuf is not self-delimiting. This means if you have a TCP connection and are sending multiple protobuf messages, there must be some other underlying protocol to take care of framing - determining where one message ends and another begins.

Let's ignore that problem for now. The actual code to serialize the message depends on which C#/protobuf library you are using. If you are using Jon Skeet's protobuf-csharp-port you might serialize it this way:

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

bookBytes is the address book, serialized to a byte array. Then use whatever socket library you want (for example TcpClient) to send the data (bookBytes) to the Java server.

I'm not convinced this will work because I think there are details about the Java server that you are not telling us.

Guido Simone
  • 7,912
  • 2
  • 19
  • 21
  • I am using the c# protobuf library v2 of Marc Gravell. Maybe therefore i haven´t the method book.ToByteArray(); It’s the Jon Skeets implementation better? I would like to send multiple messages to a single stream. The Java Sever use the following socket communication – Kaiser4you Oct 31 '12 at 21:00
  • public ControllerThread(Socket s) { this.s = s; try { 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(); } } – Kaiser4you Oct 31 '12 at 21:03
  • I am using the c# protobuf library v2 of Marc Gravell (http://code.google.com/p/protobuf-net/). Maybe therefore i haven´t the method book.ToByteArray(); It’s the Jon Skeets implementation better? – Kaiser4you Oct 31 '12 at 21:09
  • 1
    I cannot say which is better because I have never tried protobuf-net. I happened to try protobuf-csharp-port first and it worked so I stuck with it. I just scanned the docs for protobuf-net and it looks like the method you want is named Serializer.Serialize. Also I could not really read your Java comment above. Perhaps you should edit your original question and add enough of the Java code so we can see how it deserializes. Better formatting... – Guido Simone Oct 31 '12 at 21:23
  • The method Serializer.Seiralize dont return a byte arrry back. I should serialize this message to a byte array, so that i can send it to my server... – Kaiser4you Nov 01 '12 at 16:26
  • The method Serializer.Serialize dont return a byte arrry back. I should serialize this message to a byte array, so that i can send it to my server...Any help appreciated thanks! – Kaiser4you Nov 01 '12 at 16:41