我在我的应用中遇到了使用蓝牙的问题。似乎在创建了28 BluetoothSocket
/ BluetoothServerSockets
之后,所有端口都被占用了。插座不需要同时打开,因为蓝牙已启用,它只有28个插座。
可以使用Android Samples中提供的BluetoothChat样本重现。只需打开和关闭应用程序15次(该应用程序每次创建2个插槽)。在第15次,它将崩溃并将继续崩溃,直到您禁用然后重新启用蓝牙:
12-06 18:43:58.177: E/BluetoothSocket(18530): bindListen, fail to get port number, exception: java.io.IOException: read failed, socket might closed, read ret: -1
12-06 18:43:58.193: E/BluetoothChatService(18530): Socket Type: Insecurelisten() failed
12-06 18:43:58.193: E/BluetoothChatService(18530): java.io.IOException: Error: -1
12-06 18:43:58.193: E/BluetoothChatService(18530): at android.bluetooth.BluetoothAdapter.createNewRfcommSocketAndRecord(BluetoothAdapter.java:1035)
12-06 18:43:58.193: E/BluetoothChatService(18530): at android.bluetooth.BluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord(BluetoothAdapter.java:982)
12-06 18:43:58.193: E/BluetoothChatService(18530): at com.example.android.BluetoothChat.BluetoothChatService$AcceptThread.<init>(BluetoothChatService.java:280)
12-06 18:43:58.193: E/BluetoothChatService(18530): at com.example.android.BluetoothChat.BluetoothChatService.start(BluetoothChatService.java:119)
12-06 18:43:58.193: E/BluetoothChatService(18530): at com.example.android.BluetoothChat.BluetoothChat.onResume(BluetoothChat.java:131)
12-06 18:43:58.193: E/BluetoothChatService(18530): at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1185)
12-06 18:43:58.193: E/BluetoothChatService(18530): at android.app.Activity.performResume(Activity.java:5182)
12-06 18:43:58.193: E/BluetoothChatService(18530): at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2732)
12-06 18:43:58.193: E/BluetoothChatService(18530): at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2771)
12-06 18:43:58.193: E/BluetoothChatService(18530): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2235)
12-06 18:43:58.193: E/BluetoothChatService(18530): at android.app.ActivityThread.access$600(ActivityThread.java:141)
12-06 18:43:58.193: E/BluetoothChatService(18530): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
12-06 18:43:58.193: E/BluetoothChatService(18530): at android.os.Handler.dispatchMessage(Handler.java:99)
12-06 18:43:58.193: E/BluetoothChatService(18530): at android.os.Looper.loop(Looper.java:137)
12-06 18:43:58.193: E/BluetoothChatService(18530): at android.app.ActivityThread.main(ActivityThread.java:5039)
12-06 18:43:58.193: E/BluetoothChatService(18530): at java.lang.reflect.Method.invokeNative(Native Method)
12-06 18:43:58.193: E/BluetoothChatService(18530): at java.lang.reflect.Method.invoke(Method.java:511)
12-06 18:43:58.193: E/BluetoothChatService(18530): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
12-06 18:43:58.193: E/BluetoothChatService(18530): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
12-06 18:43:58.193: E/BluetoothChatService(18530): at dalvik.system.NativeStart.main(Native Method)
套接字关闭后有没有办法释放端口?
答案 0 :(得分:7)
我可以在我这里的设备上验证此行为;虽然以相同方式崩溃所需的次数因设备而异(我认为Galaxy Nexus运行4.2需要20-25次),因此端口句柄的可用数量似乎有所不同。我还可以在示例应用程序(或您的应用程序)中提供问题不是内存泄漏的信息,因为所有BluetoothSocket
实例都已由Dalvik发布和关闭。此处列出的步骤仅测试BluetoothServerSocket
上的问题,因此不清楚问题是否与此特别相关,尽管似乎不太可能。
至少在我的设备上,你甚至无法再启动应用程序,直到切换蓝牙适配器的状态,所以问题肯定在堆栈连接的底层管理中。
我会提交一个错误的步骤来重现http://b.android.com,我很乐意对它进行投票。
答案 1 :(得分:0)
最近,我不得不钻研这个解决方案。升级Android不是一种选择。
事实证明,如果每次建立/断开连接时不是破坏和重新创建mAcceptThread,而是保留原始实例并重新使用它。这可以最大限度地减少错误对您应用的影响。
从BluetoothChatService文件的connected()函数中,不要取消mAcceptThread:
public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
...
...
...
// Cancel the accept thread because we only want to connect to one device
//(Rather stay listening so comment out the cancel line!!)
//If necessary, use some other state to prevent a second connection.
//DONT CANCEL: if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;}
...
...
在AcceptThread类中,修改run()函数中的循环:
// Listen to the server socket if we're not connected
//OLD LOOP: while (mState != STATE_CONNECTED)
//(Rather use STATE_NONE so the loop will only stop when the service does)
while (mState != STATE_NONE)
在您的代码中可能还有其他事情可以正确实现这个想法。
答案 2 :(得分:0)
要重新连接我在片段中使用定时处理程序:
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(MainActivity.mac);
// Attempt to connect to the device
mChatService.connect(device, true);
要解决“重新连接超过28次时失败”的问题,我在每次失去连接时重新启动服务时都会发表评论:
//BluetoothChatService.this.start();
我也注释掉套接字关闭的所有部分:
//socket.close();
//mmServerSocket.close();
//mmSocket.close();
//mSecureAcceptThread.cancel();
并为接受线程添加了一个非空检测,并且连接thead不会失败:
if(mAdapter != null) {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,
MY_UUID_SECURE);
}else{
mAdapter = BluetoothAdapter.getDefaultAdapter();
//mState = STATE_NONE;
}
和
if(mmServerSocket != null) {
socket = mmServerSocket.accept();
}
我仍然得到随机连接丢弃,但服务重新连接,一切正常。