Закрытие HttpURLConnection до завершения ответа - PullRequest
6 голосов
/ 27 ноября 2011

Фон

Я использую HttpURLConnection на стороне клиента для получения ответа в ситуации потоковой передачи HTTP (push-сообщения с сервера). Хотя сервер может закрыть соединение, закрыв ответ, клиенту также необходимо это сделать.

Проблема

Клиент обрабатывает 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() не помог.

Предложения

Ответы [ 3 ]

5 голосов
/ 27 ноября 2011

Похоже, что этого нельзя сделать без изменения потока чтения для опроса, используя 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 голос
/ 27 ноября 2011

Если сервер не закрывает соединение, но прекращает отправку данных, in.read() заблокируется. Теперь обратите внимание, что код для HttpURLConnection.HttpInputStream.close() также попытается прочитать из потока, чтобы определить, что достигнут конец потока ( исходный код) . close(), в свою очередь, вызывается с disconnect(). И в конечном итоге ваши темы заблокированы.

Так что, похоже, вам нужно изменить свою логику. Я предполагаю, что вы закрываете соединение на основании некоторых условий. Поэтому вместо того, чтобы делать это в другом потоке, проверьте условия перед чтением следующего байта в потоке чтения, а затем отключите его.

И, кстати, Thread.interrupt() вам не поможет, поскольку он будет прерывать только потоки, ожидающие на мониторах, в то время как ваш ожидает на IO.

0 голосов
/ 24 января 2018

Другим обходным решением является обтекание входного потока в канале и его использование (Channels.newChannel), как предлагается в обходном решении, JDK-4329256 .Это приведет к закрытию основного входного потока при прерывании потока.Тем не менее, в JDK есть комментарий, что он не прерываемый.В моем тестировании это похоже на работу.Я попросил здесь для получения дополнительной информации.

...