3

Problem

I'm trying to send a protobuf message from a C# client to this Java Server but I get this exception:

java.io.StreamCorruptedException: invalid stream header: 0A290A08 
java.io.StreamCorruptedException: invalid stream header: 0A290A08
    at java.io.ObjectInputStream.readStreamHeader(Unknown Source)
    at java.io.ObjectInputStream.<init>(Unknown Source)

I'm a bit at a loss to be honest. Any help is appreciated. Thanks!

  • Java server
    public ControllerThread(Socket s){
    this.s = s; try {

        this.objectInputStream = new ObjectInputStream(s.getInputStream());
        byte size = objectInputStream.readByte();System.out.println("Server: BYTES SIZE:" +     size);
        byte[] bytes = new byte[size];
        objectInputStream.readFully(bytes);
        AddressBook adb = AddressBook.parseFrom(bytes);
        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(); } 
        } }

C# code

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

c# OutputStream

    public void SendMessage(Stream ns, byte[] msg)
    {
        byte size = (byte)msg.Length;

        try
        {
            ns.WriteByte(size);
            ns.Write(msg, 0, msg.Length);
            ns.Flush();
            ns.Close();
        }
        catch (ArgumentNullException ane)
        {
            TextBox.Text += "ArgumentNullException : {0}" + ane.ToString();
        }
        catch (Exception e)
        {
            TextBox.Text += ("Unexpected exception : {0}" + e.ToString());
        }


    }
Kaiser4you
  • 83
  • 2
  • 3
  • 10
  • 1
    Java's ObjectInputStream is probably good only for java-java communication. For C# to talk to Java, you'll need a platform neutral protocol. – irreputable Nov 01 '12 at 23:06
  • 2
    @Kaiser4you how was the message generated? And how was it written to the socket? One possibility is that you have genuinely corrupted it. – Marc Gravell Nov 01 '12 at 23:08
  • @MarcGravell it was written as a byte array. could i use ObjectInputStream with c# client? – Kaiser4you Nov 01 '12 at 23:16
  • "It is written as a byte array" is somewhat ... Vague :) I was hoping you could demonstrate exactly what you wrote onto the stream. In hindsight, @irreputable does make a good point (sorry) - that may be completely incompatible with what you wrote. We need to see what you wrote. **exactly** what you wrote, – Marc Gravell Nov 01 '12 at 23:18
  • 1
    Please post *useful* C# code .. the stuff that *writes the data* to the appropriate output stream in C#. This problem is not related to ProtocolBuffers. See the error message. I am trying to *help* the question by including an *appropriate* title. **The problem [reported] is *not* related to ProtocolBuffers.** Try to send and receive "just an int" to see. –  Nov 01 '12 at 23:22
  • but sorry you dont answer my question: could i use ObjectInputStream with c# client? because when i use java client it works...ok i edited my first post – Kaiser4you Nov 01 '12 at 23:24
  • See http://stackoverflow.com/questions/10302570/ioexceptioninvalid-stream-header-00010000-while-getting-data-from-c-sharp-ho To get around this, **do not use ObjectInputStream**, but rather a more primitive stream - e.g. a "plain" DataInputStream in Java and the corresponding "plain" binary output stream in C# –  Nov 01 '12 at 23:27
  • 2
    The c# code you post doesn't show how you then get that onto the socket. I'm happy to help (both protobuf and socket-servers are very familiar), but it is impossible to diagnose a mismatch unless you can see both ends of the pipe. I'm looking for code that: a: serializes the address-book entry, b: adds the length-prefix header, and c: how the outut of a and b get dropped onto the raw socket. – Marc Gravell Nov 01 '12 at 23:28
  • @Kaiser4you re "could I use ObjectInputStream with c# client" - that depends n exactly what you wrote :) if the bytes on the wire match what it wants: sure. If not: no. Reader and writer need to be using the same rules. – Marc Gravell Nov 01 '12 at 23:32
  • @pst thanks and what is the corresponding “plain” binary output stream in c#? – Kaiser4you Nov 02 '12 at 14:22
  • @MarcGravell thanks Ok I edited my first post, I hope, that’s what you are looking for. Could you say me now if i can use ObjectInputStream in this case? – Kaiser4you Nov 02 '12 at 14:23
  • @Kaiser4you I am struggly to say "can" vs "can't", but I will say that you *shouldn't need to*. If all you are doing is reading raw bytes, I would advise just using the raw stream API. Then check you got the same bytes that you started with. After that, it should be easy. Also: big problems if the length is more than 255 ;p – Marc Gravell Nov 02 '12 at 14:33
  • @MarcGravell: thanks but why 255? How can i change the serialization so that I could use ObjectInputStream? – Kaiser4you Nov 06 '12 at 14:53

2 Answers2

7

tldr; The problem is using ObjectInputStream (Java) which only works with data generated by ObjectOutputStream (Java). In this case the StreamCorruptedException is being generated because the stream is being given invalid data that was not generated by ObjectOutputStream (Java).

Instead, use DataInputStream (Java) to read the data generated by BinaryWriter (C#). Both of these only support "primitive" types. As long as the correct endianess is used and sign stuffing is performed as needed: integers, floats, doubles (but not Decimals), and byte arrays can be safely sent this way.

ObjectInputStream (Java):

An ObjectInputStream deserializes primitive data and objects previously written using an ObjectOutputStream [in Java].

DataInputSteam (Java):

A data input stream lets an application read primitive [..] types from an underlying input stream ..

BinaryWriter (C#):

Writes primitive types in binary to a stream and supports writing strings in a specific encoding.


Notes:

  • DataInputSteam (Java) is big-endian, but BinaryWriter (C#) must be converted to big-endian.
  • There are no issues (aside from endianness) when transferring the char/character, short, int, long, float, and double data-types as they have the same signed nature and bitwise representation in C# and Java.
  • Signed problems can arise for byte (Java, signed) vs byte (C#, unsigned). Thankfully, ProtocolBuffer will automatically handle this if given the appropriate byte[] (Java or C#).
  • Strings can provide additional fun due to slight encoding differences.
Community
  • 1
  • 1
0

So with this c# OutputStream method and DataInputStream ( Java) instead ObjectOutputSteam it works without any problems

 public void SendEndianBinaryMsg(Stream ns, byte[] msg)
    {
        byte size = (byte)msg.Length;

        try
        {

            EndianBinaryWriter writer = new EndianBinaryWriter(EndianBitConverter.Big, ns);
            writer.Write(size); 
            writer.Write(msg); 
            writer.Flush();
            ns.Close();
        }
        catch (ArgumentNullException ane)
        {
            TextBox.Text += "ArgumentNullException : {0}" + ane.ToString();
        }
        catch (Exception e)
        {
            TextBox.Text += ("Unexpected exception : {0}" + e.ToString());
        }

    }

Notes:

I get EndianBinaryWriter and EndianBitConverter from MiscUtil.

Kaiser4you
  • 83
  • 2
  • 3
  • 10