当我使用某个超时值调用BluetoothServerSocket.accept(...)
时,运行Android 7.0的Alcatel A30只会忽略超时并永久阻止。这是Android中的新错误还是这款特定手机的愚蠢行为?
这是一个简单的代码部分,用于演示问题(只需将其粘贴到任何活动中并将<uses-permission android:name="android.permission.BLUETOOTH" />
添加到您的清单中):
Thread test = new Thread() {
@Override
public void run() {
try {
System.out.println("Getting Bluetooth adapter...");
BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
System.out.println("Registering service profile...");
BluetoothServerSocket server = bt.listenUsingRfcommWithServiceRecord
("Test", UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
System.out.println("Accepting connection with timeout...");
server.accept(1000); // Android 7.0 gets stuck here rather than timing out
System.out.println("Accepted!");
} catch (Exception e) {
System.err.println("Got an error:");
e.printStackTrace();
}
}
};
test.setDaemon(true);
test.start();
预期输出(来自任何旧的Android设备;异常显示在1秒后):
Getting Bluetooth adapter...
Registering service profile...
Accepting connection with timeout...
Got an error:
java.io.IOException: Connection timed out
at android.bluetooth.BluetoothSocket.acceptNative(Native Method)
at android.bluetooth.BluetoothSocket.accept(BluetoothSocket.java:364)
at android.bluetooth.BluetoothServerSocket.accept(BluetoothServerSocket.java:113)
at line containing server.accept(1000);
我的Android 7.0 Alcatel A30的输出:
Getting Bluetooth adapter...
Registering service profile...
Accepting connection with timeout...
然后它就坐在那里直到我杀了应用程序或直到我实际连接到服务,在这种情况下我得到了
`Accepted!`
即使在我连接之前等了好几分钟之后。
更新
似乎代码示例可能会造成一些混乱(Re:已删除的答案)。通常当有人在SO上发布异常时,他们正在寻求帮助以解决问题。这是不我所追求的。通过设置超时然后不连接,我明确要求例外。问题是我不在我的Android 7.0设备上获得例外。
答案 0 :(得分:0)
似乎在接受连接时未使用超时。通过套接字发送或接收数据时(建立连接后),它用作超时。
通过超时调用BluetoothServerSocket.accept(...)
最终以setOption(...)
调用LocalSocketImpl中的SocketOptions.SO_TIMEOUT
,而后者又使用setsockopt进行设置:
SO_RCVTIMEO::设置超时值,该值指定输入函数完成之前等待的最长时间。 ...如果接收操作阻塞了这么长时间却没有接收到其他数据,那么如果没有接收到数据,它将以部分计数或errno设置为[EAGAIN]或[EWOULDBLOCK]返回。
SO_SNDTIMEO::设置超时值,以指定输出功能由于流控制阻止数据发送而阻塞的时间。如果这一次发送操作已被阻止,则它将返回一个部分计数,或者如果没有发送数据,则将errno设置为[EAGAIN]或[EWOULDBLOCK]。
答案 1 :(得分:0)
在与Android 7.0一起运行的设备上,我遇到了同样的问题。 其他设备(Android 8和9)具有预期的行为:如果接受未在其配置的超时时间内获得传入连接,则会引发IOException。
我最终要做的(不是很漂亮)是使用Timer从另一个线程关闭BluetoothServerSocket,这导致accept引发IOException,就像是超时一样。
BluetoothServerSocket mBssOutCom = mBluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord("blabla", uuid);
Timer securityTimer = new Timer();
try {
//! there seems to be a bug in android 7.0
//! that makes the connect timeout never fire. This timer will do the dirty trick
//! Should only have an effect if the bug is active
securityTimer.schedule(new TimerTask() {
@Override
public void run() {
// this code will be executed after 2 seconds
if (mBssOutCom != null) {
try {
mBssOutCom.close();
} catch (IOException e) {
e.printStackTrace();
}
mBssOutCom = null;
}
}
}, 1500);
socketCom = mBssOutCom.accept(1000);
} catch (IOException e) {
Log.d(TAG, "tryToConnect: accept timedOut");
}
securityTimer.cancel();
if (mBssOutCom != null) {
mBssOutCom.close();
mBssOutCom = null;
}
如果有人知道更好的解决方案,我很想听听!