Java ObjectInputStream генерирует EOFException с большим объектом

У меня есть этот метод для десериализации:

public static Object deserialize(byte[] data) throws IOException, ClassNotFoundException {
    ByteArrayInputStream in = new ByteArrayInputStream(data);
    ObjectInputStream is = new ObjectInputStream(in);
    Object res = is.readObject();
    is.close();
    in.close();
    return res;
}

и этот для сериализации:

public static byte[] serialize(Object obj) throws IOException {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    ObjectOutputStream os = new ObjectOutputStream(out);
    os.writeObject(obj);
    byte[] res = out.toByteArray();
    out.close();
    os.close();
    return res;
}

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

Когда я отправляю объект, содержащий до 3 элементов в arrayList, эти методы работают отлично. Однако, когда arrayList имеет 4 или более элементов, устройство, получающее объект, все еще обнаруживает, что некоторые данные "прибыли", но метод десериализации генерирует "EOFException" в "Object res = is.readObject();" линия.

Есть идеи о том, в чем проблема?

РЕДАКТИРОВАТЬ

Это класс arrayList:

import java.io.Serializable;

public class Info implements Serializable {

    public Info() {
        ...
    }

    ...
}

Это класс объекта:

import java.io.Serializable;
import java.util.ArrayList;

public class BluetoothDataContainer implements Serializable{

    private ArrayList<Info> dataList;
    private String originDevice;

    public BluetoothDataContainer(String originDevice){
        dataList= new ArrayList<Info>();
        this.originDevice = originDevice;
    }

    ...
}

Это код, который я использую для отправки объекта:

BluetoothDataContainer data = new BluetoothDataContainer(mBluetoothAdapter.getName());

...

// add needed info to variable 'data'

...

s.write(data);

Где s - это поток с методом write:

private BluetoothSocket mmSocket = bluetoothDevice.createRfcommSocketToServiceRecord(ID_CONNECTION);
private OutputStream mmOutStream = mmSocket.getOutputStream();

...

public void write(BluetoothDataContainer m) {
    try {
        mmOutStream.write(serialize(m));
    } catch (IOException e) {
        this.mContext.showToast("IOException caught in thread ConnectedThread [Bluetooth connection handler] - write() !");
    }
    //cancel();
    this.interrupt();
}

И вот как я обрабатываю объект, когда он читается:

private final Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 1:
                byte[] readBuf = (byte[]) msg.obj;
                // construct a string from the valid bytes in the buffer
                final BluetoothDataContainer data;
                try {
                    data = (BluetoothDataContainer) deserialize(readBuf);

                    ...

                } catch (IOException | ClassNotFoundException e) {
                    e.printStackTrace();
                }
                break;
            default:
                break;
        }
    }
};

И вот как я читаю объект:

private final Handler mHandler;   // value set in the constructor

...

public void run() {

    mmInStream = bluetoothSocket.getInputStream();

    byte[] buffer = new byte[1024];  // buffer store for the stream
    int bytes;

    try {
        // Read from the InputStream
        bytes = mmInStream.read(buffer);
        this.mContext.showToast("ConnectedThread [Bluetooth connection handler] data received !");

        // Send the obtained bytes to the UI activity
        mHandler.obtainMessage(1, bytes, -1, buffer).sendToTarget();

    } catch (IOException e) {
        this.mContext.showToast("IOException caught in thread ConnectedThread [Bluetooth connection handler] - run() !");
    }

}

1 ответ

Решение

Очевидно, что вы не "обменялись" всем байтовым массивом в случае сбоя.

bytes = mmInStream.read(buffer);

Вы не можете знать только из этого, читали ли вы:

  • целое сообщение
  • менее одного сообщения
  • более одного сообщения.

Поскольку у вас уже есть сокет с входным и выходным потоками, меня не удивляет, почему вы вообще создаете байтовые массивы. Просто заверните ObjectOutputStream вокруг выходного потока сокета и использовать writeObject(), На приемнике заверните ObjectInputStream вокруг сокета входного потока и использования readObject(),

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

Другие вопросы по тегам