5

I have downloaded the android sample of Bluetooth chat app to send text between two android devices using Bluetooth.

I have installed and run this app in two android devices.

I faced many problems in that code

  1. Service discovery failed exception - Fixed
  2. java.io.IOException: Software caused connection abort - Fixed
  3. java.io.IOException: Connection reset by Peer - Struck on this

1. Cleared the Service discovery failed exception:

For service discovery failed exception, In Bluetooth Chat Service, I have checked sdk version and for the sdk version which is greater than Ginger Bread,

I have used Method class to invoke RfCOMM socket connection and my first exception is solved in this approach.

Exception Code

 tmp = device.createRfcommSocketToServiceRecord(MY_UUID);

Fixed Exception code

try {
if (Build.VERSION.SDK_INT < 9) { 
try {
     tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
       } catch (IOException e1) {
            e1.printStackTrace();
       }
       } else {
   Method m = null;
  try {
  m = device.getClass().getMethod("createRfcommSocket",
        new Class[] { int.class });
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
                }
                try {
                    tmp = (BluetoothSocket) m.invoke(device, 1);
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
                }
            } catch (Exception e) {
                Log.e(TAG, "create() failed", e);
            }

2. Cleared java.io.IOException: Software caused connection abort

I have made check whether the InputStream is available

Exception Code

bytes = mmInStream.read(buffer);

Fixed Exception code

 if (mmInStream.available() > 0) {
                            // Read from the InputStream
                            bytes = mmInStream.read(buffer);

Now my problem is when I try to send data between connected devices, it throws the following error message "Connection Reset By Peer" while writing to output stream

Exception code:

public void write(byte[] buffer, int start, int end) {
mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
    if (mmOutStream !=null) {
        try {
             mmOutStream.write(buffer);
        } catch (IOException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
        }
    }
    else{
        Log.e("OutputStream Null","");
    }
}

== Update ==

Even though it shows that both devices are connected, the accept method returns fail

**06-19 10:30:23.625: D/BluetoothChatService(2630): connected
06-19 10:30:23.625: D/BluetoothChatService(2630): cancel Thread[AcceptThread,5,main]
06-19 10:30:23.625: V/BluetoothSocket.cpp(2630): abortNative
06-19 10:30:23.625: V/BluetoothSocket.cpp(2630): ...asocket_abort(50) complete
06-19 10:30:23.625: V/BluetoothSocket.cpp(2630): ...accept(50, RFCOMM) = -1 (errno 125)
06-19 10:30:23.632: E/BluetoothChatService(2630): accept() failed
06-19 10:30:23.632: E/BluetoothChatService(2630): java.io.IOException: Operation Canceled
06-19 10:30:23.632: E/BluetoothChatService(2630):   at android.bluetooth.BluetoothSocket.acceptNative(Native Method)
Siddharth
  • 9,349
  • 16
  • 86
  • 148
Sankar Ganesh PMP
  • 11,927
  • 11
  • 57
  • 90

3 Answers3

1

I had alot of problems with the chat example myself, so i tried another approach.

First you have to make one device host and the other the client, this works with the example pretty well. if you dont have this running, i can provide you with that code aswell.

Using the classes above, you get the socket for the connection. Use that to pass it to this class and then you can send using the write method. and the incoming messages are automatically parsed in the run-method (i added a message id and length to the front, thats why there is so much things going on in there)

private class ConnectedThread extends Thread {

/** the connection socket */
private final BluetoothSocket mmSocket;

/** input stream for incoming messages */
private final InputStream mmInStream;

/** output stream for outgoing messages */
private final OutputStream mmOutStream;

/**
 * save the socket and get the streams
 * 
 * @param socket
 */
public ConnectedThread(BluetoothSocket socket) {
    mmSocket = socket;
    InputStream tmpIn = null;
    OutputStream tmpOut = null;

    // Get the input and output streams, using temp objects because
    // member streams are final
    try {
        tmpIn = socket.getInputStream();
        tmpOut = socket.getOutputStream();
    } catch (IOException e) {
        e.printStackTrace();
    }

    mmInStream = tmpIn;
    mmOutStream = tmpOut;
}

/**
 * reads incoming data and splits it into single messages
 */
public void run() {
    /** buffer for a single byte message */
    byte[] buffer = new byte[1024];

    /** number of bytes returned from read() */
    int bytes;

    // Keep listening to the InputStream until an exception occurs
    while (true) {
        try {
            // read overhead from the InputStream
            bytes = mmInStream.read(buffer, 0, LEN_SIZE + LEN_TYPE);

            // if no bytes are read, wait for a new message
            if (bytes == 0)
                continue;

            // get the size bytes and convert them to int
            byte[] size_arr = new byte[LEN_SIZE];
            for (int i = 0; i < LEN_SIZE; i++)
                size_arr[i] = buffer[i];
            int size = convertByteArrayToInt(size_arr, LEN_SIZE);

            // the type is 1 byte after the size
            byte type = buffer[LEN_SIZE];

            // array for the output data
            byte[] output = new byte[size + LEN_TYPE];
            output[0] = type;

            // current position, read until cPos == size
            int cPos = 0;
            while (cPos < size) {
                // either read the buffer lenght or the remaining bytes
                int read_len = Math.min(buffer.length, size - cPos);
                bytes = mmInStream.read(buffer, 0, read_len);

                // write the bytes to the output
                for (int i = 0; i < bytes; i++)
                    output[cPos + i + LEN_TYPE] = buffer[i];

                // increase the current position
                cPos += bytes;
            }

            // add the message to the queue
            mMessageData.add(output);

            // tell the service about the new message
            mHandler.obtainMessage(BluetoothService.CONNECTION_RECV_MSG, mConnectionAddress).sendToTarget();

        } catch (IOException e) {
            // tell the service about the disconnect
            mHandler.obtainMessage(BluetoothService.CONNECTION_LOST, mConnectionAddress).sendToTarget();
            e.printStackTrace();
            break;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

/**
 * writes a byte stream to the connection
 * 
 * @param bytes
 *            the byte stream
 */
public void write(byte[] bytes) {
    try {
        mmOutStream.write(bytes, 0, bytes.length);
        mmOutStream.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

/**
 * close the socket
 */
public void cancel() {
    try {
        mmSocket.close();
    } catch (IOException e) {
    }
}

}

This worked for me, i hope it also does for you. If you have any question, feel free to ask :-)

gtRfnkN
  • 489
  • 7
  • 19
  • Thanks for your response, please refer my Update in the Question, Thanks – Sankar Ganesh PMP Jun 19 '13 at 10:35
  • What are `LEN_SIZE` and `LEN_TYPE` here, @gtRfnkN? – ericn Aug 12 '13 at 03:36
  • since you always just send a byte stream, you cannot know where the message begins and where it ends. to adress that, you need to extend the message with your own protocol including the length of the message you want to send. so i added 4 bytes at the start of the message for the length (LEN_SIZE). when receiving a message, i first read this value and then wait until all data is read. (see while (cPos < size) {...}) edit: LEN_TYPE is a single byte with the message type – gtRfnkN Aug 13 '13 at 08:16
0

You could try this, although it probably shouldn't be a final fix. When I followed that example, I had this onResume() in my main activity, and I imagine you have something similar:

@Override
public synchronized void onResume() {
    super.onResume();
    if(D) Log.e(TAG, "+ ON RESUME +");
}

Try this:

@Override
public synchronized void onResume() {
//    super.onResume();
    if(D) Log.e(TAG, "+ ON RESUME +");
}

This will stop the main activity from creating the AcceptThread more than once.

Alejandro Colorado
  • 6,034
  • 2
  • 28
  • 39
0

I think your reading is wrong. I have the line

while (true) {
    try {
        // read overhead from the InputStream
        bytes = mmInStream.read(buffer, 0, LEN_SIZE + LEN_TYPE);

in my code and it is working perfectly, without .available() and so does @gtRfnkN. From my interpretation of the Java documentation, you cannot use .available() with InputStream. See: http://docs.oracle.com/javase/6/docs/api/java/io/InputStream.html#available() particularly the part where it says "always returns zero for class InputStream".

And just in case, here is an example of my write:

    public void write(byte[] buffer){
        try{
            //a delay of 20ms occurs after each flush...
            mmOutStream.write((byte)buffer[0]);
            mmOutStream.flush();
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
strontivm
  • 59
  • 9