IOException异常在接受线程(IOException on accept thread)

2019-07-21 08:07发布

我的应用程序的一部分连接到通过蓝牙设备并正常工作正常,但偶尔会无法连接,我得到以下错误

03-11 10:29:20.328: E/BluetoothComService(8059): accept() failed
03-11 10:29:20.328: E/BluetoothComService(8059): java.io.IOException: Operation Canceled
03-11 10:29:20.328: E/BluetoothComService(8059):    at android.bluetooth.BluetoothSocket.acceptNative(Native Method)
03-11 10:29:20.328: E/BluetoothComService(8059):    at android.bluetooth.BluetoothSocket.accept(BluetoothSocket.java:316)
03-11 10:29:20.328: E/BluetoothComService(8059):    at android.bluetooth.BluetoothServerSocket.accept(BluetoothServerSocket.java:105)
03-11 10:29:20.328: E/BluetoothComService(8059):    at android.bluetooth.BluetoothServerSocket.accept(BluetoothServerSocket.java:91)
03-11 10:29:20.328: E/BluetoothComService(8059):    at com.mypackage.name.bluetooth.BluetoothService$AcceptThread.run(BluetoothService.java:298)

这是我得到异常的行

socket = mmServerSocket.accept();    

这是完整的AcceptThread

private class AcceptThread extends Thread {
    // The local server socket
    private BluetoothServerSocket mmServerSocket;
    public boolean successInit = false;

    public AcceptThread() {
        closeAllConnections();

        /*
         * if(mmServerSocket != null) { try { mmServerSocket.close(); } catch
         * (IOException e) { e.printStackTrace(); } }
         */
        BluetoothServerSocket tmp = null;

        // Create a new listening server socket
        while (!successInit) {
            try {
                tmp = mAdapter
                        .listenUsingRfcommWithServiceRecord(NAME, MY_UUID);

                successInit = true;
            } catch (Exception e) {

                successInit = false;
            }
        }

        /*
         * try { tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME,
         * MY_UUID); successInit= true; } catch (IOException e) { Log.e(TAG,
         * "listen() failed", e); tmp = null; successInit = false; }
         */
        mmServerSocket = tmp;
    }

    public void run() {
        if (D)
            Log.d(TAG, "BEGIN mAcceptThread" + this);
        setName("AcceptThread");
        BluetoothSocket socket = null;

        // Listen to the server socket if we're not connected
        while (mState != STATE_CONNECTED) {
            try {
                // This is a blocking call and will only return on a
                // successful connection or an exception
                mAdapter.cancelDiscovery();

                socket = mmServerSocket.accept();
            } catch (IOException e) {
                Log.e(TAG, "accept() failed", e);
                Log.e("Error", "This isn't connecting");
                break;
            }

            // If a connection was accepted
            if (socket != null) {
                synchronized (BluetoothService.this) {
                    switch (mState) {
                    case STATE_LISTEN:
                    case STATE_CONNECTING:
                        // Situation normal. Start the connected thread.
                        connected(socket, socket.getRemoteDevice());
                        break;
                    case STATE_NONE:
                    case STATE_CONNECTED:
                        // Either not ready or already connected. Terminate new
                        // socket.
                        try {
                            socket.close();
                        } catch (IOException e) {
                            Log.e(TAG, "Could not close unwanted socket", e);
                        }
                        break;
                    }
                }
            }
        }
        if (D)
            Log.i(TAG, "END mAcceptThread");
    }

    public void cancel() {
        if (D)
            Log.d(TAG, "cancel " + this);
        try {
            mmServerSocket.close();
        } catch (IOException e) {
            Log.e(TAG, "close() of server failed", e);
        }
    }
}     

下面是我在开始时调用函数AcceptThread ,希望关闭一切重新启动

public void closeAllConnections() {
    if (mmInStream != null) {
        try {mmInStream.close();}
        catch  (Exception e){Log.e(TAG, "close() of connect socket failed", e);}
    }
    if (mmOutStream != null) {
        try {mmOutStream.close();}
        catch (Exception e){Log.e(TAG, "close() of connect socket failed", e);}
    }
    if (mmSocket != null) {
        try {
            mmSocket.close();
            //mmSocket.connect();
        }
        catch (IOException e) {
            Log.e(TAG, "close() of connect socket failed", e);
        }
    }
}

我已经通过读蓝牙文件和SO问题,但我还没有发现任何对我的作品,并开始有点为我迷惑,因为这是我第一次通过BT连接。

注意

唯一的“修复”我发现当发生这种情况是关闭的BT适配器,强制关闭程序,重新启动BT适配器,并重新启动应用程序,这是不好的原因很明显。 我试图重新编程适配器,但我仍然无法连接。

任何人都可以看到什么可能是错误的,我BlutoothService类,这是在AcceptThread所在? 或者我怎么会去解决这个问题? 谢谢!

更新

确实如此,事实上,看起来像是连接有时关闭一个Thread ,并尝试重新连接另一个。 问题是,我想不出什么会导致它尝试连接在一个单独的Thread或如何解决它,当发生这种情况。

我可以成功复制的唯一方法是,如果我的BT设备关闭,然后我打开BT适配器关闭。 当我把一切都回到然后我得到的异常,无法连接。 我的客户,它发生在随机和定期所以我希望这些问题是相关的。

Answer 1:

嗯,我的问题的一部分是被发现了要对第三方制造商端的问题,硬件问题。 他们固件不太对,当它在读的BT地址,它偶尔会被损坏。

在软件方面,它是运行AcceptThread在两个单独的Threads定期。 我所做的修复,这是创建一个函数来关闭套接字和输入/输出流...

public void closeAllConnections()
    {
        if (mmInStream != null)
        {
            try {mmInStream.close();}
            catch  (Exception e){Log.e(TAG, "close() of connect socket failed", e);}
        }
        if (mmOutStream != null)
        {
            try {mmOutStream.close();}
            catch (Exception e){Log.e(TAG, "close() of connect socket failed", e);}
        }
        if (mmSocket != null)
        {
          try {
                mmSocket.close();
                Log.e("TAG", "close() of connect socket successfu;");
              } catch (IOException e) {
                   Log.e("TAG", "close() of connect socket failed", e);}
        }

然后在BluetoothCom类,我发现它并不总是检查的BT对象是null尝试重新启动服务之前。

private void setupService() {

    // Initialize the BluetoothChatService to perform bluetooth connections
    if((mChatService != null) && (mChatService.getState() != 0)) {
        mChatService.stop();        
    }

    // I didn't have this so it would always start a new instance of the Service
    if (mChatService == null)
        mChatService = new BluetoothService(mHandler);

    mChatService.start();
}

这似乎已经帮助了,我不再有这些问题。 不过,现在测试的三星Galaxy Tab 4,我再次有连接问题,但只有在此设备上。 也许这些信息可以帮助别人,如果我想别的了新的问题,我会更新我的答案。

注:如上所述,这款蓝牙应用程序使用修改后的代码来自Android的应用BluetoothChat。

另外,我还阅读(注意到),不同厂商实现BT栈不同,可导致头痛(至少如果哟没有足够了解的话)。



Answer 2:

虽然这是旧的文章,但所以我想写下我解决这个问题的办法,我最近接触同样的问题。

看来你的代码是从谷歌的样品BlutoothChat(因为它看起来相同的,对不起,如果我误解)。 我还创建自己的应用程序,在这个样本(在API等级10)基地。 我见到了接受(),如果我尝试到一个设备连接到其他设备故障的问题,但最后我简单地解决这个问题,删除MainActivty一些代码

在谷歌的样品主要活动就包含了许多方法,当活动的变化(启动,暂停等)。

原代码有这个

@Override
public synchronized void onResume() {
    super.onResume();
    if(D) Log.e(TAG, "+ ON RESUME +");
    if (mChatService != null) {
        if (mChatService.getState() == ChatService.STATE_NONE) {
          mChatService.start();
        }
    }
}

此代码开始聊天服务和运行AcceptThread倾听传入的连接。

当应用程序启动,这个方法会被“一次”呼叫并创建AcceptThread。 如果你做任何其他事情,使主要活动的onPause()暂停(在谷歌样本的情况下,如果单击菜单启动device_list活动的主要活动将暂停),当应用程序返回到主活动,它会调用创建AcceptThread法“一个更多的时间”,这会导致问题,因为一个线程已经运行,但你试图打断它。 并在年底发生的accept()失败的错误,并抛出java.io.IOException异常:操作已取消错误。

因此,为了避免这根本消除的onResume代码()

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

或者,如果你不想删除任何代码,因为你怕引起一些问题,把这段代码mChatService.stop()(mChatService!= NULL); 在...

@Override
public synchronized void onPause() {
    super.onPause();
    if (mChatService != null) mChatService.stop();
    if(D) Log.e(TAG, "- ON PAUSE -");
}

在我的项目这两个完美的作品。 如果活动恢复方法1不创建新的线程,如果你离开当前的活动方法2杀死所有的线程,并断开所有当前的连接,如果你已经有一个(一旦你回头会再次启动线程)。 方法1不返回任何错误,但方法2将抛出接受,如果你离开当前的活动再次失败,所以我建议使用方法1。

需要注意修改BlutoothChat,它永远不会对原有的应用程序出现谷歌的样品后,这个错误通常发生。

我看过很多帖子谈论这个问题,但没有看到任何一个拿出这个答案,所以想和大家分享这个。 希望这是有帮助的。



Answer 3:

当BluetoothServerSocket被关闭或回收垃圾应该发生的异常。 我怀疑是异常的线程的旧副本发生。 所以是这样的:当您创建新线程的旧线被取消,因此BluetoothServerSocket被关闭,因此接受正确的失败与错误。 在线的各种事件发生的调试器和/或记录检查这一点; 如设置后接受,或许在取消功能,然后检查线程ID有线路断点 - 发生前一个线程的例外呢?



文章来源: IOException on accept thread