读取从 C# 客户端发送的 ObjectInputStream 时"StreamCorruptedException: invalid stream header"



>问题

我正在尝试从 C# 客户端向此 Java 服务器发送 protobuf 消息,但出现以下异常:

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)

老实说,我有点不知所措。任何帮助,不胜感激。谢谢!

  • 爪哇服务器
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# 输出流

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;问题是使用仅适用于ObjectOutputStream (Java)生成的数据的ObjectInputStream (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

相关内容

  • 没有找到相关文章