为什么OkHttp不重用其连接?

J. *_*now 5 benchmarking http okhttp

我正在使用OkHttp 3.5.0执行http基准测试.我向同一个网址发送了数千个请求.

我希望OkHttp-client使用ConnectionPool并一遍又一遍地重用它的连接.但是如果我们调查一下,netstat我们会在TIME_WAIT状态下看到很多连接:

TCP    127.0.0.1:80           127.0.0.1:51752        TIME_WAIT
TCP    127.0.0.1:80           127.0.0.1:51753        TIME_WAIT
TCP    127.0.0.1:80           127.0.0.1:51754        TIME_WAIT
TCP    127.0.0.1:80           127.0.0.1:51755        TIME_WAIT
TCP    127.0.0.1:80           127.0.0.1:51756        TIME_WAIT
...
Run Code Online (Sandbox Code Playgroud)

经过成千上万的请求,我得到了一个 SocketException: No buffer space available (maximum connections reached?)

代码预先形成请求(Kotlin):

val client = OkHttpClient.Builder()
        .connectionPool(ConnectionPool(5, 1, TimeUnit.MINUTES))
        .build()

val request = Request.Builder().url("http://192.168.0.50").build()

while (true) {
    val response = client.newCall(request).execute()
    response.close()
}
Run Code Online (Sandbox Code Playgroud)

如果不response.close()使用response.body().string(),那么SocketException不会发生,但netstat仍会显示大量的TIME_WAIT连接,并且基准性能越来越低.

我究竟做错了什么?

PS:我试过使用Apache HttpClient及其PoolingHttpClientConnectionManager,看起来它完美无缺.但我想弄清楚OkHttp有什么问题.

toi*_*ien 6

我的版本是 3.13.0,与 3.5.0 相差不远,我也遇到了TIME_WAIT问题。

深入研究源代码后,我在CallServerInterceptor.java第 142 行发现:

if ("close".equalsIgnoreCase(response.request().header("Connection"))
    || "close".equalsIgnoreCase(response.header("Connection"))) {
   streamAllocation.noNewStreams();
}
Run Code Online (Sandbox Code Playgroud)

在 StreamAllocation.java 第 367 行中:

public void noNewStreams() {
    Socket socket;
    Connection releasedConnection;
    synchronized (connectionPool) {
      releasedConnection = connection;
      socket = deallocate(true, false, false); // close connection!
      if (connection != null) releasedConnection = null;
    }
    closeQuietly(socket);
    if (releasedConnection != null) {
      eventListener.connectionReleased(call, releasedConnection);
    }
}
Run Code Online (Sandbox Code Playgroud)

这意味着如果请求或响应中存在“Connection: close”标头,okhttp 将关闭连接

虽然问题提交已经过去了很长时间,但我希望这个答案能帮助遇到这个问题的人,祝你好运。