OkHttp调用HTTPS遇到的问题之:SocketException: Software caused connection abort: recv failed

由于需要,我要不断地调用用OkHttpClient调Https接口(链接),于是有时候会出现下面这个问题:

java.net.SocketException: Software caused connection abort: recv failed
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
    at java.net.SocketInputStream.read(SocketInputStream.java:170)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
    at sun.security.ssl.InputRecord.read(InputRecord.java:503)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
    at okhttp3.internal.io.RealConnection.connectTls(RealConnection.java:239)
    at okhttp3.internal.io.RealConnection.establishProtocol(RealConnection.java:196)
    at okhttp3.internal.io.RealConnection.buildConnection(RealConnection.java:171)
    at okhttp3.internal.io.RealConnection.connect(RealConnection.java:111)
    at okhttp3.internal.http.StreamAllocation.findConnection(StreamAllocation.java:187)
    at okhttp3.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:123)
    at okhttp3.internal.http.StreamAllocation.newStream(StreamAllocation.java:93)
    at okhttp3.internal.http.HttpEngine.connect(HttpEngine.java:296)
    at okhttp3.internal.http.HttpEngine.sendRequest(HttpEngine.java:248)
    at okhttp3.RealCall.getResponse(RealCall.java:243)
    at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:201)
    at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:163)
    at okhttp3.RealCall.execute(RealCall.java:57)

原因是因为:

在服务端/客户端单方面关闭连接的情况下,另一方依然以为
tcp连接仍然建立,试图读取对方的响应数据,导致出现
Software caused connection abort: recv failed的异常.

解决办法是:

在接收数据之前,要先判断连接状态.
在对方释放连接后,也要释放本地的连接.

然而重点是网友们的解决办法都是

通过inputstream的available()方法来判断,是否有响应结果.
如果available()的返回值为0,说明没有响应数据,可能是对方已经断开连接,
如果available()的返回值大于0,说明有响应数据.

可是我们用OkHttp出现这个错误是SocketInputStream来接收数据出错,可以从上面的错误路径中看出。是封装在okhttp3里面的。这又怎么拿SocketInputStream出来呢···黑人???

于是我回想一下我使用的过程,我是不断地调用用OkHttpClient调Https接口才出现这个问题的,单次调用没出现这个错误。而且每次调用都是新建一个OkHttpClient,不断调用上千次的时候就会不断新建对象:

OkHttpClient client = new OkHttpClient().newBuilder().hostnameVerifier(new HostnameVerifier() {
    @Override
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
}).build();

于是,为什么每次调都要新建一个client 呢,直接用单例模式就好了啊。

下面用枚举的方法实现单例模式:

public enum Client{
    INSTANCE;
    private OkHttpClient client;
    private Client(){
        client = new OkHttpClient().newBuilder().hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        }).build();
    }
    public OkHttpClient getInstance() {
        return client;
    }
}

调用的时候:

Client.INSTANCE.getInstance();

OK,不报错了,但是具体这样为什么能解决,原因还是没能搞清楚,先占个坑,免得以后忘记了,再来补充。

你可能感兴趣的:(网络编程,Java,设计模式)