android — Нужно ли нам использовать поток ошибок HttpURLConnection при возникновении IOException" />

Нужно ли нам использовать поток ошибок HttpURLConnection при возникновении IOException

Согласно техническому руководству Oracle Java, мы должны использовать поток ошибок HttpURLConnection, когда IOException брошенный

http://docs.oracle.com/javase/6 /docs/technotes/guides/net/http-keepalive.html

  

Что вы можете сделать, чтобы помочь Keep-Alive? Не отказывайтесь от связи   игнорируя тело ответа. Это может привести к простоям TCP   соединения. Это должно быть мусора, когда их нет   больше ссылки.

     

Если getInputStream () успешно возвращается, прочитайте весь ответ   тела.

     

При вызове getInputStream () из HttpURLConnection, если   Возникает IOException, перехватывает исключение и вызывает getErrorStream () для   получить тело ответа (если оно есть).

     

Чтение тела ответа очищает соединение, даже если вы не   заинтересован в самом содержании ответа. Но если тело ответа   долго, и вы не заинтересованы в остальном после просмотра   В начале вы можете закрыть InputStream. Но вы должны знать,   что больше данных может быть в пути. Таким образом, соединение не может быть   разрешено для повторного использования.

     

Вот пример кода, который соответствует приведенной выше рекомендации:

Вот пример кода

try {
        URL a = new URL(args[0]);
        URLConnection urlc = a.openConnection();
        is = conn.getInputStream();
        int ret = 0;
        while ((ret = is.read(buf)) > 0) {
          processBuf(buf);
        }
        // close the inputstream
        is.close();
} catch (IOException e) {
        try {
                respCode = ((HttpURLConnection)conn).getResponseCode();
                es = ((HttpURLConnection)conn).getErrorStream();
                int ret = 0;
                // read the response body
                while ((ret = es.read(buf)) > 0) {
                        processBuf(buf);
                }
                // close the errorstream
                es.close();
        } catch(IOException ex) {
                // deal with the exception
        }
}

Применимо ли это к платформе Android? Как я не вижу такой техники в большинстве примеров кода Android.

7 голосов | спросил Cheok Yan Cheng 17 PMpThu, 17 Apr 2014 18:51:26 +040051Thursday 2014, 18:51:26

2 ответа


0

Если вы не заинтересованы в отображении сообщения об ошибке для пользователя, закройте InputStream или вызовите disconnect в HttpURLConnection в finally блок без чтения сообщения об ошибке. Это то, что вы видите в большинстве примеров.

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

  

Это следует вызывать, когда соединение неожиданно закрывается, чтобы   сделать недействительной запись в кэше и запретить HTTP-соединение   повторное использование. HTTP сообщения отправляются последовательно, поэтому всякий раз, когда сообщение   невозможно прочитать до конца, последующие сообщения не могут быть прочитаны   либо, и соединение должно быть отброшено.

Согласно реализации Android для HttpURLConnection, в случае исключения:

  • Если ошибка не читается и InputStream закрыто, соединение будет считаться не подлежащим повторному использованию и будет закрыто.
  • Если вы прочитаете ошибку, а затем закроете InputStream, соединение будет считаться повторно используемым и добавлено в пул соединений.

Вы можете видеть на изображении ниже переменную connection & Для connectionReleased установлено значение null и true соответственно, как только все данные будут прочитаны. Обратите внимание, что getErrorStream возвращает InputStream, поэтому это действительно и в сценарии исключения.

введите описание изображения здесь

Анализ кода . Давайте рассмотрим FixedLengthInputStream один из специализированных InputStream реализация. Вот реализация метода close:

 @Override public void close() throws IOException {
    if (closed) {
        return;
    }
    closed = true;
    if (bytesRemaining != 0) {
        unexpectedEndOfInput();
    }
 }

Переменная экземпляра bytesRemaining содержит число байтов, все еще доступное в InputStream для чтения. Здесь находится неожиданная реализация метода :

protected final void unexpectedEndOfInput() {
    if (cacheRequest != null) {
        cacheRequest.abort();
    }
    httpEngine.release(false);
}

Вот release . Вызов disconnect в HttpURLConnection экземпляр ведет вызов этому методу release с параметром false в качестве параметра , Последняя проверка if обеспечивает необходимость закрытия соединения или добавления его в пул соединений для повторного использования.

public final void release(boolean reusable) {
    // If the response body comes from the cache, close it.
    if (responseBodyIn == cachedResponseBody) {
        IoUtils.closeQuietly(responseBodyIn);
    }
    if (!connectionReleased && connection != null) {
        connectionReleased = true;
        // We cannot reuse sockets that have incomplete output.
        if (requestBodyOut != null && !requestBodyOut.closed) {
            reusable = false;
        }
        // If the headers specify that the connection shouldn't be reused, don't reuse it.
        if (hasConnectionCloseHeader()) {
            reusable = false;
        }
        if (responseBodyIn instanceof UnknownLengthHttpInputStream) {
            reusable = false;
        }
        if (reusable && responseBodyIn != null) {
            // We must discard the response body before the connection can be reused.
            try {
                Streams.skipAll(responseBodyIn);
            } catch (IOException e) {
                reusable = false;
            }
        }
        if (!reusable) {
            connection.closeSocketAndStreams();
            connection = null;
        } else if (automaticallyReleaseConnectionToPool) {
            HttpConnectionPool.INSTANCE.recycle(connection);
            connection = null;
        }
    }
}

Общий код, которым вы обрабатываете IOException, поток ошибок читается, а затем закрывается, обеспечивает возможность многократного использования Соединения и добавления его в пул соединений. В тот момент, когда все данные считываются из InputStream из Connection добавляется в пул соединений. Вот реализация метода read для FixedLengthInputStream

@Override public int read(byte[] buffer, int offset, int count) throws IOException {
        Arrays.checkOffsetAndCount(buffer.length, offset, count);
        checkNotClosed();
        if (bytesRemaining == 0) {
            return -1;
        }
        int read = in.read(buffer, offset, Math.min(count, bytesRemaining));
        if (read == -1) {
            unexpectedEndOfInput(); // the server didn't supply the promised content length
            throw new IOException("unexpected end of stream");
        }
        bytesRemaining -= read;
        cacheWrite(buffer, offset, read);
        if (bytesRemaining == 0) {
            endOfInput(true);
        }
        return read;
    }

Когда переменная bytesRemaining становится равной 0, endOfInput а > вызывается, что будет вызывать метод release с true

protected final void endOfInput(boolean reuseSocket) throws IOException {
        if (cacheRequest != null) {
            cacheBody.close();
        }
        httpEngine.release(reuseSocket);
    }
ответил Manish Mulimani 6 Maypm14 2014, 14:04:38
0

Если это задокументировано для Java, то оно является обязательным для платформы Android.

ответил user207421 12 Maypm14 2014, 14:05:37

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132