Как убедиться, что все данные отправляются до закрытия Android BluetoothSocket
Я делаю приложение для Android, которое будет общаться между телефонами через Bluetooth. Чтобы сэкономить заряд батареи, я бы не хотел постоянно держать соединение Bluetooth открытым. Поэтому каждый раз, когда я собираюсь отправить сообщение, я открываю соединение, отправляю сообщение, очищаю, затем закрываю.
Моя проблема в том, что иногда, но не всегда, принимающий телефон выдает мне пресловутое "java.io.IOException: закрыт сокет bt, чтение return: -1". Я вижу, что документация BluetoothSocket гласит
BluetoothSocket является потокобезопасным. В частности, close() всегда будет немедленно прерывать текущие операции и закрывать сокет.
Тем не менее, общая страница Bluetooth гласит:
Когда вы закончите с BluetoothSocket, всегда вызывайте close(). Это немедленно закроет подключенный сокет и освободит все связанные внутренние ресурсы.
Вот выдержка из ветки, куда я отправляю сообщение.
localSocket = device.createRfcommSocketToServiceRecord(MY_UUIDS[0]);
localSocket.connect();
Log.d(TAG, "Correctly Connected on " + MY_UUIDS[0]);
OutputStream rawOutputStream = localSocket.getOutputStream();
ObjectOutputStream messageOutputStream = new ObjectOutputStream(rawOutputStream);
// Actually send the message
messageOutputStream.writeObject(message);
messageOutputStream.flush();
rawOutputStream.flush();
messageOutputStream.close();
rawOutputStream.close();
localSocket.close();
Вот выдержка из ветки, где я принимаю входящие соединения:
InputStream rawInputStream = socket.getInputStream();
ObjectInputStream messageInputStream = new ObjectInputStream(rawInputStream);
BluetoothMessage joinMessage = (BluetoothMessage) messageInputStream.readObject();
BluetoothDevice device = socket.getRemoteDevice();
messageInputStream.close();
rawInputStream.close();
socket.close();
socket = null;
Я понимаю, что сбрасывания и закрытия являются избыточными, но дело в том, что иногда из-за аппаратных задержек сокет закрывается на отправляющей стороне до того, как будет отправлено все сообщение.
Я могу подтвердить, что ВСЕ сообщения поступают идеально каждый раз, независимо от того, насколько быстро я продолжаю отправлять их... ЕСЛИ я не закрываю сокет. Тем не менее, я знаю, что всегда лучше закрывать сокет.
Итак, КАК я могу гарантировать, что все сообщения отправляются ДО вызова socket.close()? Очевидно, что flush() и stream close() не делают то, что должны быть, в противном случае сообщение будет полностью отправлено независимо от того, когда я вызываю socket.close().
1 ответ
Прежде всего, я бы сказал, что ваше первое предположение не совсем верно. Если два устройства будут постоянно обмениваться данными, возможно, было бы более эффективно поддерживать соединение открытым.
Но что касается вашего вопроса, это правда, что иногда, входящие байты, возможно, не были полностью прочитаны, когда выдается IOException.
Единственный способ убедиться в этом - реализовать какой-то протокол, в котором вы:
- Запись данных с одного устройства
- Прочитайте это с удаленного устройства
- Ответьте с некоторого рода "ack" с удаленного устройства, чтобы подтвердить, что ваши данные были прочитаны полностью.
- Закрывайте сокет только после того, как вы получили "ack".