【问题标题】:Closing an HttpURLConnection before the response is complete在响应完成之前关闭 HttpURLConnection
【发布时间】:2011-11-27 06:27:59
【问题描述】:

背景

我在客户端使用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() 也无济于事。

建议?

【问题讨论】:

    标签: java httpurlconnection


    【解决方案1】:

    如果不更改读取线程以使用InputStream.available() 进行轮询并在没有可用字节时休眠一小段时间,则似乎无法完成此操作,同时检查一些标志以查看线程是否应该结束。

    解决方案是只使用 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;
    }
    

    原帖中的循环可以保持原样,读取线程在调用HttpGetConnection.close()后很快就会死掉。

    【讨论】:

    • 如果是这样的话,我认为没有人应该在不使用可用方法的情况下编写这样的代码。
    【解决方案2】:

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

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

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

    【讨论】:

    • 谢谢。唯一的问题是大多数时候,读取线程被阻塞,所以没有机会检查条件。 InputStream 上没有允许超时的读取方法。
    • 您可以使用available() 查看流中是否有任何内容。如果没有,您可以暂停并在此之后重新检查您的情况,这样您就不会阻塞空流。
    • 请看我的回答 - 已经承认这一事实并且它需要一个不太理想的轮询/睡眠/检查周期。还是谢谢。
    • @AlexGitelman 找不到源代码。你介意更新你的链接吗?
    【解决方案3】:

    另一种解决方法是将输入流包装在 Channel 中并使用它 (Channels.newChannel),如解决方法 JDK-4329256 中所建议的那样。这将导致在线程中断时关闭底层输入流。但是,JDK 中有一条注释说它并不是真正可中断的。在我的测试中,它似乎有效。我已经向here 询问了更多信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-31
      • 2020-02-16
      • 2017-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-21
      相关资源
      最近更新 更多