读取从C#客户端发送的ObjectInputStream时出现“StreamCorruptedException:invalid stream header”

问题

我正在尝试从C#客户端向此Java Server发送protobuf消息,但是我得到了以下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.(Unknown Source) 

说实话,我有点不知所措。 任何帮助表示赞赏。 谢谢!

  • Java服务器
  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#代码

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

tldr; 问题是使用ObjectInputStream (Java)它只适用ObjectOutputStream (Java)生成的数据。 在这种情况下,正在生成StreamCorruptedException ,因为流被赋予了非ObjectOutputStream (Java)生成的无效数据。

而是使用DataInputStream (Java)读取BinaryWriter (C#)生成的数据。 这两者都只支持“原始”类型。 只要使用正确的字节顺序并根据需要执行符号填充 :整数,浮点数,双精度(但不是十进制数)和字节数组都可以通过这种方式安全地发送。

ObjectInputStream (Java)

ObjectInputStream反序列化以前使用ObjectOutputStream [在Java中]编写的原始数据和对象

DataInputSteam (Java)

数据输入流允许应用程序从基础输入流中读取原语[..]类型

BinaryWriter (C#)

二进制中的原始类型写入流并支持以特定编码写入字符串。


笔记:

  • DataInputSteam(Java)是big-endian ,但BinaryWriter(C#)必须转换为big-endian 。
  • 传递char/charactershortintlongfloatdouble数据类型时没有问题(除了字节顺序),因为它们在C#和Java中具有相同的签名性质和按位表示。
  • byte (Java, signed)byte (C#, unsigned)可能会出现签名问题。 值得庆幸的是,如果给定适当的byte[] (Java or C#)ProtocolBuffer将自动处理此问题
  • 由于轻微的编码差异,字符串可以提供额外的乐趣。

所以用这个c#OutputStream方法和DataInputStream (Java)代替ObjectOutputSteam它没有任何问题

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

笔记:

我从MiscUtil获得EndianBinaryWriterEndianBitConverter