在okhttp中使用http2时,为啥对同一主机的多个请求不只使用一个connectoin

Posted

技术标签:

【中文标题】在okhttp中使用http2时,为啥对同一主机的多个请求不只使用一个connectoin【英文标题】:When using http2 in okhttp, why multi requests to the same host didn't use just one connectoin在okhttp中使用http2时,为什么对同一主机的多个请求不只使用一个connectoin 【发布时间】:2015-12-14 00:14:46 【问题描述】:

我想测试一下okhttp的http2功能。而且我以异步方式向同一主机发出多个请求。但是,我发现,它涉及到多连接,因为协议是h2,它应该只使用一个连接,对吧? 代码如下。 啊,我用的是okhttp2.5

public class Performance 
    private final OkHttpClient client = new OkHttpClient();
    private final Dispatcher dispatcher = new Dispatcher();
    private final int times = 20;

    public Performance()
        dispatcher.setMaxRequestsPerHost(2);
        client.setDispatcher(dispatcher);

        // Configure the sslContext
        // MySSLSocketFactory mySSLSocketFactory = new MySSLSocketFactory();
        // client.setSslSocketFactory(mySSLSocketFactory);
        // client.setHostnameVerifier(new HostnameVerifier() 
        //     public boolean verify(String s, SSLSession sslSession) 
        //         return true;
        //     
        // );
    
    public void run()throws Exception
        for(int i=0; i<times; i++) 
            Request request = new Request.Builder()
                .url("https://http2bin.org/delay/1")
                .build();
            client.newCall(request).enqueue(new Callback() 
                public void onFailure(Request request, IOException e) 
                    e.printStackTrace();
                

                public void onResponse(Response response) throws IOException 
                    System.out.println(response.headers().get("OkHttp-Selected-Protocol"));
                
            );
        
    
    public static void main(String[] args)throws Exception
        Performance performance = new Performance();
        performance.run();
    

【问题讨论】:

请说明您如何知道您的请求通过多个连接。 我得到的结论有以下几个原因: 1. 修改调度器的 maxRequestsPerHost 时,结果会相应地发生变化,这就是我使用 /delay/1 路径进行测试的原因。 maxRequestsPerHost 表示连接数或请求数,尽管多个请求可以在一个连接中执行? ; 2.我用/get等其他路径和HTTP1.1的性能对比,不管我设置多少请求,似乎都没有性能差异。 您能确认您获得的是 HTTP/2 连接吗?请注意,您需要桌面上的 Jetty-ALPN。 是的,我可以。 response.headers().get("OkHttp-Selected-Protocol") 显示使用的协议,我得到了 h2。我已经使用 -Xbootclasspath/p:C:/Users/zfz/.m2/repository/org/mortbay/jetty/alpn/alpn-boot/8.1.4.v20150727/alpn-boot- 添加了 Jetty-ALPN 支持8.1.4.v20150727.jar 在 VM 选项中。 【参考方案1】:

OkHttp 中有a bug,其中多个同时请求各自创建自己的套接字连接,而不是协调共享连接。这仅在同时创建连接时发生。通过在第二次连接之前产生 500 毫秒来解决问题。

【讨论】:

如果存在这个错误,这意味着在许多情况下我的应用程序不会受益于 HTTP/2 的多路复用特性,对吧?因为如果我想等待 500 毫秒来创建第二个连接,可能使用 HTTP1.1 就足够了。而且,我做了一个实验,在client.newCall(reqeust).enqueue后面加上Thread.sleep(1000),好像一直都像以前一样使用多连接。 错误链接对吗?我认为这与这个问题无关。您的错误描述是相关的,但是,我无法使用睡眠来解决它。期待你的帮助,谢谢~ 他们在 OKHttp3.0+ 中修复了这个错误吗? 我也想知道。这个问题在 3.x 中已经修复了吗? 其实现在应该已经修复了,不过还有一个相关的问题需要注意。 github.com/square/okhttp/pull/3207

以上是关于在okhttp中使用http2时,为啥对同一主机的多个请求不只使用一个connectoin的主要内容,如果未能解决你的问题,请参考以下文章

译文——OkHttp, 安卓和Java应用的HTTP&HTTP2.0客户端

Okhttp3、http2多路复用POST请求高峰负载时响应时间长

非加密http2.0

HTTP2 可用,但服务器拒绝使用它,为啥会这样?

http2 似乎不适用于 OkHttp3 和 retrofit2

OKHttp Android没有通过http2 alpn连接到nginx