OkHttp 的 SocketConnection 异常,即使它应该在连接失败时重试

问题描述 投票:0回答:1

尽管使用 OkHttpClient 并将 retryOnConnectionFailure 设置为 true(默认),但可能导致 SocketConnection 异常的原因是什么?我们在 Kotlin 中使用 okHttpClientVersion = "4.10.0" 并引入了一个拦截器来在服务器 IP 更改时关闭套接字连接。多个调用并行运行,如果拦截器关闭一个连接中的套接字,则正在进行的所有其他连接都会失败,从而导致 SocketException。

根据文档(https://www.javadoc.io/doc/com.squareup.okhttp3/okhttp/3.0.1/okhttp3/OkHttpClient.Builder.html#retryOnConnectionFailure-boolean-),如果它看到陈旧的池连接。因此,它应该重试并在下一次重试时获得一个新的套接字连接,并且它应该可以工作。但是,我们仍然收到 SocketConnection 异常。是什么导致了这个问题?

kotlin sockets okhttp
1个回答
0
投票

如果您在使用 OkHttp 时遇到 SocketException 错误,这可能是由于连接在关闭后没有从连接池中正确删除。

OkHttp内部管理连接和路由,有一个连接池可以复用连接。当使用

connection.socket().close()
关闭连接时,它不会自动从连接池中删除。如果这个关闭的连接后来被重用,OkHttp 会抛出一个 SocketException 错误。

要解决此问题,您需要从连接池中删除已关闭的连接。一种方法是调用

connectionPool.evictAll()
从池中删除所有连接。但是,如果您有其他想要保留在池中的活动连接,这可能并不理想。

另一种方法是使用连接拦截器在关闭后从池中删除关闭的连接。这是一个从池中删除关闭连接的示例拦截器:

class ConnectionPoolCleanupInterceptor implements Interceptor {
  private final ConnectionPool connectionPool;

  public ConnectionPoolCleanupInterceptor(ConnectionPool connectionPool) {
    this.connectionPool = connectionPool;
  }

  @Override public Response intercept(Chain chain) throws IOException {
    // Call the next interceptor in the chain
    Response response = chain.proceed(chain.request());

    // Remove the connection from the pool if it's closed
    if (response.body() != null && response.body().source().exhausted()) {
      connectionPool.evict(chain.connection());
    }

    return response;
  }
}

然后您可以将此拦截器添加到您的 OkHttp 客户端:

OkHttpClient client = new OkHttpClient.Builder()
  .connectionPool(new ConnectionPool())
  .addInterceptor(new ConnectionPoolCleanupInterceptor(connectionPool))
  .build();

有了这个拦截器,关闭的连接会自动从连接池中移除,防止重用关闭的连接导致的SocketException错误。

© www.soinside.com 2019 - 2024. All rights reserved.