Search code examples
javahttpsokhttpsocket-timeout-exception

http request normal,but change https request is frequent occur SocketTimeoutException


I was recently trying to change http to https, but the result wasn't so happier because of the frequent request timeouts after changing to https, which made me have a very bad user experience; my current solution is Use a thread pool to perform okhttp synchronization requests, which are normal for http requests. I want a solution, thank you!

first step: init okhttpclient

 public static class MyHttpUtils{
    private static  MyHttpUtils myHttpUtils;

    private OkHttpClient okHttpClient;

    private MyHttpUtils(){
        initClient();
    }

    private void initClient() {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.writeTimeout(60_000, TimeUnit.MILLISECONDS);
        builder.connectTimeout(60_000,TimeUnit.MILLISECONDS);
        builder.readTimeout(60_000,TimeUnit.MILLISECONDS);
        HttpsUtils httpsUtils = HttpsUtils.getInstance();

        HttpsUtils.SSLParams sslParams = httpsUtils.getSslSocketFactory();
        builder.sslSocketFactory(sslParams.sSLSocketFactory,sslParams.trustManager)
                .hostnameVerifier(httpsUtils.hostnameVerifier());//check hostname
        okHttpClient = builder.build();
    }


    public static MyHttpUtils getInstance(){
        if(myHttpUtils == null){
            synchronized (MyHttpUtils.class){
                if(myHttpUtils == null){
                    myHttpUtils = new MyHttpUtils();
                }
            }
        }
        return  myHttpUtils;
    }

    public OkHttpClient getOkHttpClient() {
        return okHttpClient;
    }
}

Second step: create thread pool

public static class  ThreadPool{
    private static  ThreadPool threadPool = new ThreadPool();

    private ExecutorService service = new ThreadPoolExecutor(0 /* corePoolSize */,
            Integer.MAX_VALUE /* maximumPoolSize */, 60L /* keepAliveTime */, TimeUnit.SECONDS,
            new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp ConnectionPool", true));

    public static ThreadPool getInstance(){
        return threadPool;
    }

    public void  execute(Runnable runnable){
        service.execute(runnable);
    }
}

Third step: create Runnable

private Runnable  createRunnable(){
   return new Runnable() {
       @Override
       public void run() {

           try {
               okhttp3.Request.Builder requestBuilder = new okhttp3.Request.Builder();
               requestBuilder.url(url).tag(this).build();
               okhttp3.Request request = requestBuilder.build();
               okhttp3.Response response = client.newCall(request).execute();
               if(response.code() == 200){
                  synchronized (this){
                      successSum++;
                  }
                   Log.e(MainActivity.class.getSimpleName(),"success="+successSum);
                   Log.e("myResult","result="+response.body().string());
               }else{
                  synchronized (this){
                      failSum++;
                  }
                   Log.e(MainActivity.class.getSimpleName(),"failSum="+failSum+"==code="+response.code());
               }
           } catch (IOException e) {
               client.connectionPool().evictAll();
              synchronized (this){
                  exceptionSum++;
              }
               Log.e(MainActivity.class.getSimpleName(),"exceptionSum="+exceptionSum+"==msg="+ e.toString());
           }
       }
   };
}

the fourth step:send request

@Override
public void onClick(View view) {
    switch (view.getId()){
        case R.id.btn_request:
            successSum = 0;
            failSum = 0;
            exceptionSum = 0;
            int i = 10;
            while (i>0){
                requestSync();
                i--;
            }

            break;
    }
}

Method: requestSync()

private void requestSync(){
    ThreadPool.getInstance().execute(createRunnable());
}

final result: occur SocketTimeoutException enter image description here

I used sample data when testing, and the request success rate is about 60%; this result makes my application very unfriendly, but I'm not sure why this is so, I hope to get a solution, thank you


Solution

  • This problem has been solved. Because the synchronous mode request is used, ssl will block other threads from connecting to the host when the handshake occurs. The solution is to directly change the synchronous mode to asynchronous mode.