0

I am making an android app that will communicate between phones via bluetooth. In order to save battery, I would like to refrain from keeping a bluetooth connection open all the time. So each time I'm going to send a message, I open up a connection, send the message, flush, then close.

My problem is that sometimes, but not always, the receiving phone gives me the notorious "java.io.IOException: bt socket closed, read return: -1". I see that the BluetoothSocket documentation states

BluetoothSocket is thread safe. In particular, close() will always immediately abort ongoing operations and close the socket.

However, the general Bluetooth page states:

When you're done with your BluetoothSocket, always call close(). Doing so will immediately close the connected socket and release all related internal resources.

Here is the excerpt from the thread where I send the message.

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

Here is an excerpt from the thread where I accept incoming connections:

                    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;

I realize that the flushes and closes are redundant, but the fact is that sometimes due to hardware delays, the socket closes on the sending side before all of the message is sent.

I can confirm that ALL messages arrive perfectly every time, no matter how rapidly I keep sending them....IF I don't close the socket. However, I know it is always best practice to close a socket.

So HOW do I ensure that all of the message is sent BEFORE calling socket.close()? Obviously the flush()'s and stream close()'s are doing not doing what they should be, otherwise, the message would be completely sent regardless of when I call socket.close().

MagicGuy52
  • 571
  • 1
  • 6
  • 11
  • You don't need any of the flushes, and you only need to close the object output stream. It's hard to believe that the `close()` is abortive, i.e. aborts all transfers in progress. Is this really true in practice? – user207421 Jun 11 '17 at 02:17

1 Answers1

0

First of all, i would say that your first assumption is not entirely correct. If the two devices are going to be communicating constantly, it might be more efficient to actually keep the connection open.

But regarding your question, it is true that sometimes, the incoming bytes might not have been fully read when an IOException is thrown.

The only way to make sure is to implement some sort of protocol where you:

  1. Write data from one device
  2. Read it from the remote device
  3. Reply with some sort of "ack" from the remote device to confirm that your data has been read entirely.
  4. Close the socket only after you have received the "ack".
Roberto Betancourt
  • 2,375
  • 3
  • 27
  • 35
  • Yes, this is actually what I ended up doing. In the app I may have as many as seven devices that communicate with the server device, so I ruled out keeping the connection open for battery reasons. I was worried that the ack approach wouldn't work because the remote device would need to close the socket after sending the ack which might cause the same problem as the original message sending. So, to solve this, I have the remote device call read() returning negative one until an exception occurs to know when the first device has closed its socket. – MagicGuy52 Jun 12 '17 at 14:39