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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13186848/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 11:48:44  来源:igfitidea点击:

"StreamCorruptedException: invalid stream header" when reading ObjectInputStream sent from C# client

c#javastream

提问by Kaiser4you

Problem

问题

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

我正在尝试从 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)

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

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

  • Java server
  • 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# code

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="[email protected]";
    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

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


    }

回答by

tldr;The problem is using ObjectInputStream (Java)which only workswith data generated by ObjectOutputStream (Java). In this case the StreamCorruptedExceptionis being generated because the stream is being given invaliddata that was notgenerated by ObjectOutputStream (Java).

tldr; 问题是使用ObjectInputStream (Java)which仅适用ObjectOutputStream (Java). 在这种情况下,StreamCorruptedException正在生成 ,因为流被赋予了不是由 生成的无效数据。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 endianessis usedand sign stuffingis performed as needed: integers, floats, doubles (but not Decimals), and byte arrays can be safely sent this way.

相反,使用DataInputStream (Java)读取由 生成的数据BinaryWriter (C#)。这两者都只支持“原始”类型。只要正确字节序使用符号堆砌如需要进行:整数,浮点数,双打(但不是小数),和字节数组可以安全地发送这种方式。

ObjectInputStream (Java):

ObjectInputStream (Java)

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

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

DataInputSteam (Java):

DataInputSteam (Java)

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

数据输入流允许应用程序从底层输入流读取原始 [..] 类型..

BinaryWriter (C#):

BinaryWriter (C#)

Writes primitive typesin 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 doubledata-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 thisif given the appropriate byte[] (Java or C#).
  • Strings can provide additional fun due to slight encoding differences.
  • DataInputSteam (Java) 是 big-endian,但BinaryWriter (C#) 必须转换为 big-endian
  • 传输, , , , 和数据类型时没有问题(除了字节序)char/character,因为它们在 C# 和 Java 中具有相同的有符号性质和按位表示。shortintlongfloatdouble
  • byte (Java, signed)vs可能会出现签名问题byte (C#, unsigned)。值得庆幸的是,ProtocolBuffer会自动处理,如果给予适当的byte[] (Java or C#)
  • 由于轻微的编码差异,字符串可以提供额外的乐趣。

回答by Kaiser4you

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

因此,使用此 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());
        }

    }

Notes:

笔记:

I get EndianBinaryWriterand EndianBitConverterfrom MiscUtil.

我从MiscUtil得到EndianBinaryWriterEndianBitConverter