首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Android HttpUrlConnection EOFException

Android HttpUrlConnection EOFException
EN

Stack Overflow用户
提问于 2013-10-08 21:12:38
回答 7查看 17.6K关注 0票数 32

我想知道安卓系统上是否存在HttpUrlConnection和POST请求的已知问题。当我们从安卓客户端发出帖子请求时,我们正在体验间歇性的 EOFExceptions。重新尝试相同的请求最终将有效。下面是一个示例堆栈跟踪:

代码语言:javascript
复制
java.io.EOFException
at libcore.io.Streams.readAsciiLine(Streams.java:203)
at libcore.net.http.HttpEngine.readResponseHeaders(HttpEngine.java:579)
at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:827)
at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:283)
at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:497)
at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134)

有许多类似的bug报告和帖子需要堆叠溢出,但我无法理解是否真的存在问题,如果是的话,Android的哪些版本受到影响,以及建议的修复/解决方案是什么。

以下是我所指的一些类似报告:

下面是一个潜在的Android框架修复程序

我知道在前Froyo的连接池中有一个有毒连接的问题,但是这些问题只发生在新的ICS+设备上。如果以后的设备有问题的话,我预计会有一些官方的Android文档来解决这个问题。

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2013-11-30 16:40:06

我们的结论是,Android平台存在一个问题。我们的解决方法是捕获EOFException并重试请求N次。下面是伪代码:

代码语言:javascript
复制
private static final int MAX_RETRIES = 3;

private ResponseType fetchResult(RequestType request) {
    return fetchResult(request, 0);
}

private ResponseType fetchResult(RequestType request, int reentryCount) {
    try {
        // attempt to execute request
    } catch (EOFException e) {
        if (reentryCount < MAX_RETRIES) {
            fetchResult(request, reentryCount + 1);
        }
    }
    // continue processing response
}
票数 12
EN

Stack Overflow用户

发布于 2014-04-03 07:04:11

HttpURLConnection库在内部维护一个连接池。因此,每当发送请求时,它首先检查池中是否已经存在一个现有连接,并根据该连接决定创建一个新连接。

这些连接不过是套接字,默认情况下这个库不会关闭这些套接字。有时可能会发生这样的情况,即当前未使用并存在于池中的连接(套接字)不再可用,因为服务器可能会在一段时间后选择终止连接。现在,由于连接即使被服务器关闭,库也不知道它,并假设连接/套接字仍然连接。因此,它使用这个陈旧的连接发送新请求,因此我们得到了EOFException。

处理此问题的最佳方法是在发送每个请求后检查响应头。服务器总是在终止连接(HTTP1.1)之前发送一个" connection : Close“。因此,您可以使用getHeaderField()并检查"Connection“字段。另外要注意的是,服务器只在即将终止连接时发送此连接字段。因此,在正常情况下(当服务器不关闭连接时),您需要对此进行编码,以获得"null“。

票数 7
EN

Stack Overflow用户

发布于 2014-05-21 22:45:28

这种解决办法往往是可靠的和有表现力的:

代码语言:javascript
复制
static final int MAX_CONNECTIONS = 5;

T send(..., int failures) throws IOException {
    HttpURLConnection connection = null;

    try {
        // initialize connection...

        if (failures > 0 && failures <= MAX_CONNECTIONS) {
            connection.setRequestProperty("Connection", "close");
        }

        // return response (T) from connection...
    } catch (EOFException e) {
        if (failures <= MAX_CONNECTIONS) {
            disconnect(connection);
            connection = null;

            return send(..., failures + 1);
        }

        throw e;
    } finally {
        disconnect(connection);
    }
}

void disconnect(HttpURLConnection connection) {
    if (connection != null) {
        connection.disconnect();
    }
}

此实现依赖于以下事实:可以用服务器打开的默认连接数是5 (Froyo - KitKat)。这意味着可能存在多达5个陈旧的连接,每个连接都必须关闭。

每次尝试失败后,Connection:close请求属性将导致底层HTTP在调用connection.disconnect()时关闭套接字。通过重试6次(最大连接+ 1),我们确保最后一次尝试总是会给出一个新的套接字。

如果没有活动的连接,请求可能会经历额外的延迟,但这肯定比EOFException更好。在这种情况下,最后的发送尝试不会立即关闭新打开的连接。这是唯一可以进行的实际优化。

您可以自己配置系统属性,而不是依赖神奇的5默认值。请记住,这个属性是由KitKat的ConnectionPool.java中的静态初始化程序块访问的,在旧版本的Android中也是这样工作的。因此,在您有机会设置属性之前,可以使用该属性。

代码语言:javascript
复制
static final int MAX_CONNECTIONS = 5;

static {
    System.setProperty("http.maxConnections", String.valueOf(MAX_CONNECTIONS));
}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19258518

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档