проблема в отправке сериализуемых объектов с помощью ObjectInputStream


Фрагмент кода сервера:

 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 3

4 ответа:

Если вы создаете несколько экземпляров ObjectInputStream последовательно для одного и того же входного потока сокета, это кажется плохой идеей. Если сервер записывает несколько объектов в один и тот же выходной поток, то существует информация, связанная с сериализацией, которая отправляется только один раз на уникальный объект, и только первый экземпляр ObjectInputStream на клиенте сможет надежно прочитать это. Использование только одного экземпляра ObjectInputStream на входной поток сокета и одного ObjectOutputStream экземпляр на выходной поток сокета, вероятно, самая безопасная реализация.

Кроме того, если вы записываете Несколько объектов в один и тот же экземпляр ObjectOutputStream на стороне сервера (т. е. несколько вызовов writeObject ()), это может привести к проблемам с заголовком потока из-за потенциально множественных ссылок на одни и те же объекты (обычно вложенные ссылки), когда они считываются входным потоком клиента

Эта проблема возникает, когда поток вывода объекта обертывает сокет выходной поток, так как во время обычной сериализации вторая и более поздние ссылки на объект не описывают объект, а только используют ссылку. ObjectInputStream клиента по какой-то причине не восстанавливает объекты должным образом из-за разницы в информации заголовка, которую он ожидает (он не сохраняет ее от предыдущих вызовов readObject ()); это, кажется, происходит только с потоками сокетов, а не с файловым вводом-выводом и т. д. Эта проблема не возникает с Первым readObject() вызовите, но скорее второй и последующие.

Если вы хотите продолжать использовать один и тот же поток сокетов для записи нескольких объектов, вам потребуется что-то вроде следующего в коде сервера:

objectOut.reset()
objectOut.writeObject(foo);
Вызов reset() повторно инициализирует поток, игнорируя состояние всех объектов, ранее отправленных по потоку. Это гарантирует, что каждый объект отправляется полностью без ссылок типа дескриптора, которые обычно используются для сжатия данных ObjectOutputStream и предотвращения дублирование. Это менее эффективно, но не должно быть никакого повреждения данных при чтении клиентом.

Из документации для 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.

Я бы предположил, что вы пытаетесь прочитать объект до того, как он был записан в поток объектов, или тот, где выходной поток не был сброшен.

Вы пытаетесь прочитать в объекте типа 'Object'. Так вот как он был сериализован? Вам нужно убедиться, что Вы читаете объект в тот же класс, из которого он был написан, помните те надоедливые предупреждения serialVersionUID, которые приходят? Это ключ к сериализации и реконструкции объектов, отсюда необходимость подбора классов. Также причина, по которой вам нужно обновить свой UID при изменении структуры класса.

Возможно, вы пытаетесь прочитать несколько раз один и тот же объект из потока, в то время как сервер записал объект только один раз.

Или вы пытаетесь использовать ObjectInputStream перед созданием соответствующего ObjectOutputStream, и это делает недействительным связь между ними. ObjectOutputStream записывает заголовок потока сериализации при его создании, и если он не был создан до соответствующего ObjectOutputStream, этот заголовок теряется.