【问题标题】:problem in sending serializable objects using ObjectInputStream使用 ObjectInputStream 发送可序列化对象的问题
【发布时间】:2011-03-06 10:00:04
【问题描述】:

来自服务器代码的 sn-p :

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


          }
        }

来自客户端的sn-p:

//////////////
    /// 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

我该如何解决?

【问题讨论】:

  • 你能发布你是如何“多次”阅读它的吗?您是否多次调用readObject()?还是您正在建立新的联系?
  • readObject() 存在于客户端的按钮监听器中,当我第一次单击它时,客户端读取它成功,但下一次单击时出现异常。

标签: java sockets serializable


【解决方案1】:

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

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

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

如果您想继续使用同一个套接字流来写入多个对象,您需要在服务器代码中添加如下内容:

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

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

【讨论】:

  • 我做了 objectOut.reset() 但我仍然得到同样的异常。
  • @Waseem - 您是否在整个套接字通信会话中只使用一个 ObjectInputStream 实例和一个 ObjectOutputStream 实例?
  • @Waseem - 看起来客户端上的第二个 ActionListener() 为每个套接字会话创建多个 ObjectInputStream 实例,每次调用 actionPerformed() 一个。我会尝试将对构造函数的调用移至代码部分,在该代码部分中,客户端通过套接字输出流创建 ObjectOutputStream 实例到服务器。在整个会话中使用此 ObjectInputStream 的相同实例。
【解决方案2】:

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

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

当根对象的所有字段和 它引用的对象是 完全恢复。此时 对象验证回调是 根据他们的顺序执行 登记的优先事项。回调 由对象注册(在 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.

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

【讨论】:

    【解决方案3】:

    您正在尝试读取“对象”类型的对象。是这样连载的吗?您需要确保将对象读入与写入对象相同的类中,还记得出现的那些讨厌的 serialVersionUID 警告吗?这是对象序列化和重构的关键,因此需要匹配类。这也是您需要在类结构更改时更新 UID 的原因。

    【讨论】:

      【解决方案4】:

      也许您正试图从流中多次读取同一个对象,而服务器只写入一次该对象。

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

      【讨论】:

      • 这些都不会导致此异常。
      猜你喜欢
      • 2015-09-28
      • 2013-11-25
      • 2018-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-25
      • 1970-01-01
      相关资源
      最近更新 更多