我在客户端使用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()
也无济于事。
建议?
答案 0 :(得分:5)
如果没有改变读取线程使用InputStream.available()
进行轮询并且在没有可用字节的情况下睡眠很短的时间,看起来这样做是不可能的,同时检查一些标志以查看线程是否应该端。
解决方案是使用Apache HTTP Components。通过将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;
}
原始帖子中的循环可以保持原样,并且在调用HttpGetConnection.close()
后,阅读主题将很快死亡。
答案 1 :(得分:1)
如果服务器未关闭连接但停止发送数据,in.read()
将阻止。现在,请注意HttpURLConnection.HttpInputStream.close()
的代码将尝试从流中读取以确定到达流的末尾(source code)。
反过来,close()
来自disconnect()
。最终你的线程被阻止了。
所以看来你需要改变你的逻辑。我假设您根据某些条件关闭连接。因此,在读取线程中读取下一个字节之前,不要在不同的线程中检查条件,然后断开连接。
顺便说一下,Thread.interrupt()
不会帮助你,因为它只会在你的等待IO时中断在监视器上等待的线程。
答案 2 :(得分:0)
另一种解决方法是将输入流包装在Channel中并使用该{({1}}),如JDK-4329256的变通方法中所建议的那样。这将导致在线程中断时关闭底层输入流。但是,JDK中有一条评论说它不是真正可以中断的。在我的测试中它似乎工作。我已经向here询问了更多信息。