在响应完成之前关闭HttpURLConnection

背景

我在客户端使用HttpURLConnection在HTTP流(服务器推送)情况下使用响应。 虽然服务器可以通过关闭响应来关闭连接,但客户端也需要能够执行此操作。

问题

客户端在单独的线程中处理InputStream ,如下所示:

 @Override public void run() { try { for (int b = in.read(); b >= 0; b = in.read()) { char c = (char) b; // Do something with the character // ... } } catch (IOException e) { } } 

因此,当我从发起连接的线程调用HttpURLConnection.disconnect() (重要的信息是它与处理输入的线程不同),该调用将无限期挂起。 我甚至一夜之间离开了它,它仍然悬挂着。 即使调用Thread.interrupt()也无济于事。

建议?

看起来如果不改变读取线程以使用InputStream.available()进行轮询并且在没有可用字节的情况下hibernate一段短的perdiod,一直检查一些标志以查看线程是否应该结束。

解决方案是仅使用Apache HTTP组件。 通过将GET请求的代码封装在一个类中,可以很容易地将其集成到现有代码中。

 public class HttpGetConnection implements AutoCloseable { public HttpGetConnection(String url) throws IOException { client = new DefaultHttpClient(); get = new HttpGet(url); response = client.execute(get); entity = response.getEntity(); } public InputStream getContent() throws IOException { content = entity.getContent(); return content; } @Override public void close() throws Exception { get.abort(); try { content.close(); } catch (IOException e) { } } private HttpClient client; private HttpGet get; private HttpResponse response; private HttpEntity entity; private InputStream content; } 

原始post中的循环可以保持原样,并且在调用HttpGetConnection.close()之后读取线程将很快死亡。

如果服务器没有关闭连接但停止发送数据, in.read()将阻止。 现在,请注意HttpURLConnection.HttpInputStream.close()的代码也将尝试从流中读取以确定到达流的末尾( 源代码) 。 反过来, close()disconnect()调用。 最终你的线程被阻止了。

所以你似乎需要改变你的逻辑。 我假设您根据某些条件关闭连接。 因此,在读取线程中读取下一个字节之前,不要在不同的线程中检查条件,然后断开连接。

顺便说一句, Thread.interrupt()不会帮助你,因为它只会在你的等待IO时中断在监视器上等待的线程。

另一种解决方法是将输入流包装在Channel中并使用它( Channels.newChannel ),如JDK-4329256的变通方法中所建议的那样 。 这将导致在线程中断时关闭底层输入流。 但是,JDK中有一条评论说它不是真正可以中断的。 在我的测试中它似乎工作。 我在这里要求了解更多信息。