【问题标题】:How to control the okHttpClient connections size?如何控制 okHttpClient 连接大小?
【发布时间】:2019-07-08 19:24:22
【问题描述】:

我正在调试我的 Android 应用程序中的一个问题。我发现根本原因是文件描述符超出了限制。经过进一步调查,我发现该应用程序打开了太多套接字。我使用 OkHttpClient 2.5 进行所有网络通信,因此我想知道我应该如何限制我的连接池大小。下面是我的代码sn-p:

    OkHttpClient okHttpClient = new OkHttpClient().setConnectTimeout(TIMEOUT);
    ConnectionPool connectionPool = new ConnectionPool(MAX_IDLE_CONNECTIONS,
                                                       KEEP_ALIVE_DURATION_MS);
    okHttpClient.set(connectionPool);

    @RequireArgsConstructor
    public HttpEngineCallable implements Callable<IHttpResponse>
    {
      private final String url;

      public IHttpResponse call () throws Exception 
      {
         try
        {
           Request request = Request.Builder().url(url).build();
           Call call = okHttpClient.newCall(request);
           Response rawResponse = call.execute();
           return new OkHttpResponse(rawResponse);
        }
        catch (Exception e)
        {
           throw new IllegalStateException(e);
        }
    }  

    private final Function<IHttpResponse, T> httpResponseParser = new Function<IHttpResponse, T>()
    {
        @Nullable
        @Override
        public T apply(@Nullable IHttpResponse httpResponse)
        {
            if(httpResponse == null)
            {
               return null;
            }

            InputStream stream = httpResponse.getBody();
            JsonParser parser = null;
            T result = null;

            try
            {
               parser = jsonFactory.createParser(stream);
               result = strategy.parseData(parser);
            }
            catch (Exception e)
            {
               log.error("Unable to convert {} with {}.", stream, strategy, e);
            }
            finally
            {
               IOUtils.closeQuietly(parser);
               IOUtils.closeQuietly(stream);
            } 

          return result;
        }
     };

     Future<T> future = executorService.submit(new HttpEngineCallable(url));
     Future<V> finalFuture = Futures.transform(future, httpResponseParser, executorService);

     T result = timeoutExecutorService.submit(new Runnable() 
     {
        try
        { 
          T result = finalFuture.get(CLIENT_TIMEOUT, TIMEUNIT)
          if (result == null)
          { 
            notify onFailure listeners
          }
          else
          {
            notify onSuccess Listeners
          }
        }
        catch(Exception ex)
        {
          notify onFailure listeners
        }
     } 

所以我对这个实现有几个问题:

  1. 我的 CLIENT_TIMEOUT 比 OkHttp ConnectTimeout 短。如果我的finalFuture.get(CLINT_TIMEOUT, TIMEUNIT) 抛出超时异常,我在解析器函数中的 finally 块是否仍会被执行?我指望它关闭我的连接。
  2. 如何限制我的 ConnectionPool 的大小?如果连接超出限制,我是否可以自动回收最旧的连接?

【问题讨论】:

  • Re (1), finally 块总是被执行。这就是他们的目的。
  • @EJP 确切地说,我担心以下两种情况 1.) finalFuture.get() 超时时间较短。由于这个 get() 强制执行 httpResponseParser.apply(),所以这部分执行从未发生过。 2.) HttpEngineCallable.call() 发生异常。我不确定执行路径是否仍会到达 httpResponseParser.apply() 部分。你知道在上述两种情况下,执行路径是否仍然会到达包含 finally 块的 httpResponseParser.apply() 部分?

标签: java android future okhttp


【解决方案1】:

我们遇到了类似的问题,即打开的文件描述符过多会导致我们的应用程序崩溃。

问题是我们为每个请求创建了一个 OkHttpClient。默认情况下,每个 OkHttpClient 都带有自己的连接池,这当然会增加连接/线程/文件句柄的数量并阻止池中的正确重用。

我们通过在单例中手动创建 全局 ConnectionPool 解决了这个问题,然后将其传递给构建实际 OkHttpClient 的 OkHttpClient.Builder 对象。

...
builder.connectionPool(GLOBAL_CONNECTION_POOL);
OkHttpClient client = builder.build();
...

这仍然允许使用OkHttpClient.Builder 进行按请求配置,并确保所有OkHttpClient 实例仍在使用公共连接池。 然后,我们能够正确调整全局连接池的大小。

【讨论】:

  • 如果你能提供代码就太好了
猜你喜欢
  • 1970-01-01
  • 2015-05-17
  • 2018-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-19
  • 2012-06-11
  • 2016-03-24
相关资源
最近更新 更多