使用ObjectInputStream发送可序列化对象的问题

时间:2010-06-21 16:34:03

标签: java sockets serializable

来自服务器代码的

片段:

 public void run() {
        try {
          // Create data input and output streams
          ObjectInputStream inputFromClient = new ObjectInputStream(
            socket.getInputStream());
          ObjectOutputStream outputToClient = new ObjectOutputStream(
            socket.getOutputStream());

          while (true) {

         cop = inputFromClient.readObject();

         String[][] m1=new String[][] {{"1", "1","1"}};
         Object xx=new getSerialModel(m1);
         outputToClient.reset();
         outputToClient.writeObject(xx);

         outputToClient.flush();


          }
        }
来自客户的

摘录:

//////////////
    /// sockt jop
    try {
    // Create a socket to connect to the server
   socket = new Socket("127.0.0."+Math.round(50+Math.random()*50), 8000);

    // Create an output stream to send data to the server
   toServer = new ObjectOutputStream(socket.getOutputStream());
   toServer.flush();

  }
  catch (IOException ex) {
    msgArea.append('\n' + ex.toString() + '\n');
  }
///////////////////
//***
///////////////////
buttonSave.addActionListener(new ActionListener()

{ public void actionPerformed(ActionEvent ev)

{

System.out.println("Saving data is not implemented yet.");
        String[][] m1={{"0","0","0"}};
        for ( int i = 0 ; i < tableModel.getRowCount() ; i++ ){
            { for ( int j = 0 ; j < tableModel.getColumnCount() ; j++ )
                    m1[i][j]=(String)tableModel.getValueAt(i, j) ;
            }
        }

        getSerialModel obt =new getSerialModel(m1);

        try{
            toServer.reset();
        toServer.writeObject(obt);
       toServer.flush();


        }
        catch (Exception ex) {
     msgArea.append("cant reach the server its may be off" + '\n');
   }

}

});
// button send msg
    buttonsendtest.addActionListener(new ActionListener()

{ public void actionPerformed(ActionEvent ev)

{
        try{


       fromServer = new ObjectInputStream(socket.getInputStream());

       Object mdata = fromServer.readObject();
       tableModel.setDataVector((((getSerialModel)mdata).getmodel()), columnNames);
       table.updateUI();

        }
        catch (Exception ex) {
            System.out.print(ex.getStackTrace());
     msgArea.append("cant reach the server its may be off "+ ex.toString() + '\n');
   }

}
});

当我尝试多次从服务器读取可序列化对象时,我得到了这个异常,第一次接收者成功读取它。

java.io.StreamCorruptedException: invalid stream header: 00007571

我该如何解决?

4 个答案:

答案 0 :(得分:7)

如果要为同一个套接字输入流创建多个串联的ObjectInputStream实例,这似乎是一个坏主意。如果服务器正在将多个对象写入同一输出流,则存在与每个唯一对象仅发送一次的序列化相关信息,并且只有客户端上的第一个ObjectInputStream实例才能可靠地读取此信息。每个套接字输入流只使用一个ObjectInputStream实例,每个套接字输出流只使用一个ObjectOutputStream实例可能是最安全的实现。

另外,如果要将多个对象写入服务器端的相同 ObjectOutputStream实例(即多个writeObject()调用),这可能会导致流标题客户端输入流读取相同对象(通常是嵌套引用)时可能会多次引用的问题

当对象输出流包装套接字输出流时会发生此问题,因为在正常序列化期间,对对象的第二次和后续引用不描述对象,而是仅使用引用。客户端的ObjectInputStream由于某些原因而不能正确地重建对象,因为它期望的头信息不同(它不会保留以前的readObject()调用);这似乎只发生在套接字流,而不是文件I / O等。第一次 readObject()调用不会发生此问题,而是第二次和后续调用。

如果要继续使用相同的套接字流来编写多个对象,则需要在服务器代码中使用以下内容:

objectOut.reset()
objectOut.writeObject(foo);

reset()调用重新初始化流,忽略先前沿流发送的任何对象的状态。这可确保每个对象都完整地发送,而不需要通常用于压缩ObjectOutputStream数据并避免重复的句柄类型引用。效率较低,但客户端读取时不应有数据损坏。

答案 1 :(得分:0)

ObjectInputStream.readObject()的文档中,我引用:

  

从ObjectInputStream中读取一个对象。的班级   对象,类的签名,   和非瞬态的值   和类的非静态字段   读取所有超类型。   类的默认反序列化可以   使用writeObject和覆盖   readObject方法。引用的对象   通过这个对象被传递阅读   这样一个完整的等效图表   对象由重建   的readObject。

     

根对象在其所有字段和时都完全恢复   它引用的对象是   完全恢复。此时此刻   对象验证回调是   按顺序执行   注册优先事项回调   由对象注册(在   readObject特殊方法)就像它们一样   单独修复。

     

对于InputStream和类的问题,会抛出异常   不应该反序列化。所有   例外是致命的   InputStream并将其留在   不确定的国家;它取决于   调用者忽略或恢复流   状态。

Specified by:
    readObject in interface ObjectInput

Returns:
    the object read from the stream 
Throws:
    ClassNotFoundException - Class of a serialized object cannot be found. 
    InvalidClassException - Something is wrong with a class used by serialization. 
    StreamCorruptedException - Control information in the stream is inconsistent. 
    OptionalDataException - Primitive data was found in the stream instead of objects. 
    IOException - Any of the usual Input/Output related exceptions.

我猜你是在尝试将一个对象写入对象流之前读取一个对象,或者是一个未刷新输出流的对象。

答案 2 :(得分:0)

您正在尝试读取“对象”类型的对象。它是如何序列化的?你需要确保你正在将对象读入它所写的同一个类中,还记得那些讨厌的serialVersionUID警告吗?这是对象序列化和重构的关键,因此需要匹配类。此外,您需要在类结构更改时更新UID。

答案 3 :(得分:-1)

也许你试图从流中多次读取相同的对象,而服务器只写了一次对象。

或者您在创建相应的ObjectOutputStream之前尝试使用ObjectInputStream,这会使两者之间的通信无效。 ObjectOutputStream在创建时写入序列化流标头,如果它未在相应的ObjectOutputStream之前创建,则该标头将丢失。