根据Oracle Java的技术指南,我们应该HttpURLConnection在IOException抛出时消耗错误流
http://docs.oracle.com/javase/6/docs/technotes/guides/net/http-keepalive.html
你能做些什么来帮助Keep-Alive?不要忽略响应主体而放弃连接.这样做可能会导致TCP连接空闲.当它们不再被引用时,需要进行垃圾收集.
如果getInputStream()成功返回,请读取整个响应正文.
从HttpURLConnection调用getInputStream()时,如果发生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
}
}
Run Code Online (Sandbox Code Playgroud)
这适用于Android平台吗?因为我在大多数Android代码示例中都没有看到这样的技术.
如果你不感兴趣的显示错误信息给用户,关闭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();
}
}
Run Code Online (Sandbox Code Playgroud)
实例变量bytesRemaining包含仍待InputStream读取的字节数.这是unexpectedEndOfInput方法实现:
protected final void unexpectedEndOfInput() {
if (cacheRequest != null) {
cacheRequest.abort();
}
httpEngine.release(false);
}
Run Code Online (Sandbox Code Playgroud)
这是发布方法实现.调用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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
您共享的代码,在其中处理IOException,读取错误流然后关闭,确保Connection可重用并添加到连接池.所有的数据读取瞬间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;
}
Run Code Online (Sandbox Code Playgroud)
当bytesRemaining变量变为0时,调用endOfInput,这将进一步调用release带true参数的方法,这将确保连接被合并.
protected final void endOfInput(boolean reuseSocket) throws IOException {
if (cacheRequest != null) {
cacheBody.close();
}
httpEngine.release(reuseSocket);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2134 次 |
| 最近记录: |