BluetoothServerSocket accept()在HTC Desire上没有返回

时间:2013-09-19 22:30:18

标签: android-bluetooth android

我正在开发基于众所周知的BluetoothChat示例的蓝牙应用程序。 基本上,使用此应用程序,客户端可以将一些数据包发送到服务器。

我使用两个Xperia智能手机(Xperia X8和Xperia Sola,Android 2.1和4.0)测试了应用程序,一切正常:它们都可以充当客户端或服务器。

不幸的是,如果我使用HTC Desire(android 2.3)作为服务器,它将无法接受来自其中一个Xperia客户端的传入连接。似乎客户端connect()返回好像一切正​​常,但服务器在其accept()上被阻止,好像什么都没发生一样。

相关代码段:

1。 “接受线程”

private class BluetoothAcceptThread extends Thread
    {
        private final BluetoothServerSocket serverSocket;

        public BluetoothAcceptThread()
        {
            BluetoothServerSocket tmpSocket = null;      

            try   
            {
                Method m = bluetoothAdapter.getClass().getMethod("listenUsingRfcommOn", new Class[] {int.class});
                tmpSocket = (BluetoothServerSocket) m.invoke(bluetoothAdapter, APP_BT_CHANNEL);
            }
            catch (NoSuchMethodException e)
            {
                e.printStackTrace();
            }
            catch (InvocationTargetException e)
            {
                Log.e(MainActivity.ERROR_TAG, "BluetoothAcceptThread listen() (with reflection) failed", e);
            }
            catch (IllegalAccessException e)
            {
                e.printStackTrace();
            }

            serverSocket = tmpSocket;
            Log.d(MainActivity.DEBUG_TAG, "BluetoothAcceptThread ServerSocket created");
        }

        @Override
        public void run()
        {
            BluetoothSocket socket = null;

            try
            {
                Log.d(MainActivity.DEBUG_TAG, "BluetoothAcceptThread calling accept()...");
                socket = serverSocket.accept();
                Log.d(MainActivity.DEBUG_TAG, "BluetoothAcceptThread accept() returned");
            }
            catch (IOException e)
            {
                Log.e(MainActivity.ERROR_TAG, "BluetoothAcceptThread accept() failed: " + e.getMessage());
            }

            if (socket != null)
            {
                Log.d(MainActivity.DEBUG_TAG, "BluetoothAcceptThread accept() successfully");

                synchronized (BluetoothManager.this)
                {
                    if (currentState == SocketState.LISTENING || currentState == SocketState.CONNECTING)
                        startBluetoothConnection(socket);  // all is ok, it can proceed

                    else if (currentState == SocketState.INACTIVE || currentState == SocketState.CONNECTED)
                        cancel(socket);     
                }
            }
        }

        @Override
        public void cancel()
        {
            try
            {
                serverSocket.close();
                Log.d(MainActivity.DEBUG_TAG, "BluetoothAcceptThread ServerSocket closed");
            }
            catch (IOException e)
            {
                Log.e(MainActivity.ERROR_TAG, "BluetoothAcceptThread close() failed", e);
            }
        }

        private void cancel(BluetoothSocket newSocket)
        {
            try
            {
                newSocket.close();
                Log.d(MainActivity.DEBUG_TAG, "BluetoothAcceptThread client socket closed");
            }
            catch (IOException e)
            {
                Log.e(MainActivity.ERROR_TAG, "BluetoothAcceptThread client socket close() failed", e);
            }
        }
    }

2。 “连线”

private class BluetoothConnectThread extends Thread
    {
        private final BluetoothSocket socket;
        private final BluetoothDevice device;

        public BluetoothConnectThread(BluetoothDevice d)
        {
            device = d;
            BluetoothSocket tmpSocket = null;  

            try   
            {
                Method m = device.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
                tmpSocket = (BluetoothSocket) m.invoke(device, APP_BT_CHANNEL);
            }
            catch (NoSuchMethodException e)
            {
                e.printStackTrace();
            }
            catch (InvocationTargetException e)
            {
                Log.e(MainActivity.ERROR_TAG, "BluetoothConnectThread create() (with reflection) failed", e);
            }
            catch (IllegalAccessException e)
            {
                e.printStackTrace();
            }

            socket = tmpSocket;
            Log.d(MainActivity.DEBUG_TAG, "BluetoothConnectThread client socket created");
        }

        @Override
        public void run()
        {
            stopBluetoothDiscovery();  // otherwise it will slow down the connection

            try
            {
                socket.connect();
                Log.d(MainActivity.DEBUG_TAG, "BluetoothConnectThread connect() successfully");
            }
            catch (IOException e)
            {
                Log.e(MainActivity.ERROR_TAG, "BluetoothConnectThread connect() failed", e);
                String deviceName = device != null ? device.getName() : "none";
                connectionFailed(deviceName);  // notify UI thread
                return;
            }

            synchronized (BluetoothManager.this)
            {
                bluetoothConnectThread = null;   
            }

            startBluetoothConnection(socket);  // create the "Communication" Thread
        }

        @Override
        public void cancel()
        {
            try
            {
                socket.close();
                Log.d(MainActivity.DEBUG_TAG, "BluetoothConnectThread client socket closed");
            }
            catch (IOException e)
            {
                Log.e(MainActivity.ERROR_TAG, "BluetoothConnectThread close() failed", e);
            }
        }
    }

第3。 “通信线程”(在BluetoothChat示例中也称为ConnectedThread)

private class BluetoothCommunicationThread extends Thread
    {
        private final BluetoothSocket socket;
        private final InputStream inputStream;
        private final OutputStream outputStream;

        public BluetoothCommunicationThread(BluetoothSocket s)
        {
            socket = s;
            InputStream in = null;
            OutputStream out = null;

            try
            {
                in = socket.getInputStream();
                out = socket.getOutputStream();
            }
            catch (IOException e)
            {
                Log.e(MainActivity.ERROR_TAG, "BluetoothCommunicationThread failed to get streams", e);
            }

            inputStream = in;
            outputStream = out;
        }

        @Override
        public void run()
        {
            byte[] buffer = new byte[BT_BUFF_SIZE];
            int readBytes;    

            while (true)
            {
                try
                {
                    readBytes = inputStream.read(buffer, 0, buffer.length);

                    if (readBytes != -1)
                    {
                        Message message = messageHandler.obtainMessage(DATA_MSG, readBytes, -1, buffer);
                        message.sendToTarget();  // notify to UI thread the bytes counter
                    }
                    else
                    {
                        BluetoothDevice device = socket.getRemoteDevice();
                        String deviceName = device != null ? device.getName() : "none";
                        connectionLost(deviceName);
                        break;
                    }
                }
                catch (IOException e)
                {
                    Log.e(MainActivity.ERROR_TAG, "BluetoothCommunicationThread read() failed", e);
                    BluetoothDevice device = socket.getRemoteDevice();
                    String deviceName = device != null ? device.getName() : "none";
                    connectionLost(deviceName);
                    break;
                }
            }
        }

        public void write(byte[] buffer)
        {
            try
            {
                outputStream.write(buffer);
            }
            catch (IOException e)
            {
                Log.e(MainActivity.ERROR_TAG, "BluetoothCommunicationThread write() failed", e);
            }
        }

        @Override
        public void cancel()
        {
            try
            {
                socket.close();
                Log.d(MainActivity.DEBUG_TAG, "BluetoothCommunicationThread socket closed");
            }
            catch (IOException e)
            {
                Log.e(MainActivity.ERROR_TAG, "BluetoothCommunicationThread close() failed", e);
            }
        }
    }

问题的步骤如下:

  1. HTC Desire服务器调用accept()
  2. Xperia客户端致电connect()
  3. connect返回,就像建立连接一样
  4. HTC上没有任何事情发生,始终在accept()
  5. 上被阻止
  6. Xperia客户端认为它已连接,因此它创建了CommunicationThread并调用阻塞read();此函数抛出java.io.IOException: Software caused connection abort,可能是因为套接字未连接。
  7. 最后这些是相关的记录:

    Xperia客户端:

    09-20 00:44:23.562    9106-9106/com.powertester D/[PowerTester Debug]﹕ BluetoothConnectThread client socket created
    09-20 00:44:25.704    9106-9579/com.powertester D/[PowerTester Debug]﹕ BluetoothConnectThread connect() successfully
    09-20 00:44:25.734    9106-9579/com.powertester D/[PowerTester Debug]﹕ BluetoothCommunicationThread started and I/O streams ready
    09-20 00:44:25.764    9106-9589/com.powertester E/[PowerTester Error]﹕ BluetoothCommunicationThread read() failed
            java.io.IOException: Software caused connection abort
            at android.bluetooth.BluetoothSocket.readNative(Native Method)
            at android.bluetooth.BluetoothSocket.read(BluetoothSocket.java:333)
            at android.bluetooth.BluetoothInputStream.read(BluetoothInputStream.java:96)
            at com.powertester.net.BluetoothManager$BluetoothCommunicationThread.run(BluetoothManager.java:518)
    09-20 00:44:25.844    9106-9106/com.powertester D/[PowerTester Debug]﹕ BluetoothCommunicationThread socket closed
    

    HTC服务器

    09-19 15:47:07.591    2422-2422/com.powertester D/[PowerTester Debug]﹕ BluetoothAcceptThread ServerSocket created
    09-19 15:47:07.591    2422-2484/com.powertester D/[PowerTester Debug]﹕ BluetoothAcceptThread calling accept()...
    

    真的奇怪的是,如果用作客户端的HTC Desire ,其中一个Xperia用作服务器。

    那么,是我的应用程序的问题还是HTC Desire蓝牙堆栈中的问题?

1 个答案:

答案 0 :(得分:1)

经过一些麻烦后,我意识到问题在于反射本身以及蓝牙频道的明确使用。

使用常规方式(即the not-hidden bluetooth methods),我的应用效果非常好。