我正在使用HTTPClient库,我遇到了一个奇怪的问题,即Socket.close()调用永远不会返回,从而导致超时异常。这种情况偶尔会发生,我可以在大约 10% 的时间内重现它。
我在 Android 4.2、4.3 和 4.4 上看到了这个问题。
这是我为此问题创建的Android错误票证:
http://code.google.com/p/android/issues/detail?id=66102
知道为什么 Socket.close 会永远挂起吗?我怎样才能避免这种情况?谢谢!
02-17 20:48:31.800: E/AndroidRuntime(12871): FATAL EXCEPTION: FinalizerWatchdogDaemon
02-17 20:48:31.800: E/AndroidRuntime(12871): Process: com.vblast.sample, PID: 12871
02-17 20:48:31.800: E/AndroidRuntime(12871): java.util.concurrent.TimeoutException: org.apache.http.impl.conn.PoolingHttpClientConnectionManager.finalize() timed out after 10 seconds
02-17 20:48:31.800: E/AndroidRuntime(12871): at libcore.io.Posix.close(Native Method)
02-17 20:48:31.800: E/AndroidRuntime(12871): at libcore.io.BlockGuardOs.close(BlockGuardOs.java:75)
02-17 20:48:31.800: E/AndroidRuntime(12871): at libcore.io.IoBridge.closeSocket(IoBridge.java:188)
02-17 20:48:31.800: E/AndroidRuntime(12871): at java.net.PlainSocketImpl.close(PlainSocketImpl.java:162)
02-17 20:48:31.800: E/AndroidRuntime(12871): at java.net.Socket.close(Socket.java:317)
02-17 20:48:31.800: E/AndroidRuntime(12871): at org.apache.http.impl.BHttpConnectionBase.close(BHttpConnectionBase.java:346)
02-17 20:48:31.800: E/AndroidRuntime(12871): at org.apache.http.impl.conn.LoggingManagedHttpClientConnection.close(LoggingManagedHttpClientConnection.java:83)
02-17 20:48:31.800: E/AndroidRuntime(12871): at org.apache.http.impl.conn.CPoolEntry.closeConnection(CPoolEntry.java:70)
02-17 20:48:31.800: E/AndroidRuntime(12871): at org.apache.http.impl.conn.CPoolEntry.close(CPoolEntry.java:96)
02-17 20:48:31.800: E/AndroidRuntime(12871): at org.apache.http.pool.AbstractConnPool.shutdown(AbstractConnPool.java:127)
02-17 20:48:31.800: E/AndroidRuntime(12871): at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.shutdown(PoolingHttpClientConnectionManager.java:347)
02-17 20:48:31.800: E/AndroidRuntime(12871): at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.finalize(PoolingHttpClientConnectionManager.java:168)
02-17 20:48:31.800: E/AndroidRuntime(12871): at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:187)
02-17 20:48:31.800: E/AndroidRuntime(12871): at java.lang.Daemons$FinalizerDaemon.run(Daemons.java:170)
02-17 20:48:31.800: E/AndroidRuntime(12871): at java.lang.Thread.run(Thread.java:841)
我混淆了使用Socket.setSoLinger()
作为我的连接超时设置,从而导致长时间挂起,从而导致超时异常。
这就是Socket.setSoLinger()
的作用:
如果套接字处于连接模式,并且设置了SO_LINGER选项 对于具有非零延迟时间的插座,并且该套接字具有 未传输的数据,则 close() 应阻止最多当前 延迟间隔,直到传输所有数据。
http://pubs.opengroup.org/onlinepubs/009695399/functions/close.html
这里真正的问题是您泄漏了连接,要求它在完成时关闭。您需要检查您的代码以确保关闭在最终块中。您可能还必须自己调用 HttpURLConnection.disconnect()。