连接重置大文件上载时的异常

时间:2017-11-13 07:09:28

标签: java android ssl upload okhttp

我成功上传了较小的文件< 10MB通过okhttp(3.8.1)通过https。

  • 在不同的Android 6和7设备上使用Testet。
  • buildtools 27.0.0
  • 编译了SDK 27

使用以下库:

  • com.squareup.okhttp3:okhttp:3.8.1
  • com.squareup.okhttp3:测井拦截:3.8.1
  • com.squareup.okhttp3:okhttp-的URLConnection:3.8.1

但是如果我尝试使用100-200MB左右的相同代码,则上传失败并显示异常:

javax.net.ssl.SSLException: Write error: ssl=0x559a6311d0: I/O error during system call, Connection reset by peer
    at com.android.org.conscrypt.NativeCrypto.SSL_write(Native Method)
    at com.android.org.conscrypt.OpenSSLSocketImpl$SSLOutputStream.write(OpenSSLSocketImpl.java:771)
    at okio.Okio$1.write(Okio.java:79)
    at okio.AsyncTimeout$1.write(AsyncTimeout.java:180)
    at okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:171)
    at okio.RealBufferedSink.write(RealBufferedSink.java:41)
    at okhttp3.internal.http1.Http1Codec$ChunkedSink.write(Http1Codec.java:325)
    at okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:171)
    at okio.RealBufferedSink.write(RealBufferedSink.java:91)
    at de.fhdo.gobsis.mobile.libraries.ProgressRequestBody.writeTo(ProgressRequestBody.java:73)
    at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:62)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
    at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
    at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
    at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
    at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
    at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:185)
    at okhttp3.RealCall.execute(RealCall.java:69)
    at com.example.services.Uploadervice.onHandleIntent(UploadCaseService.java:274)
    at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:66)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:148)
    at android.os.HandlerThread.run(HandlerThread.java:61)

设备正在运行且应用程序处于前台。 我在Android IntentService中使用以下代码:

ProgressRequestBody body = new ProgressRequestBody(
  getApplicationContext(),
  new ProgressRequestBody.UploadInfo(Uri.fromFile(json), json.length()),
      new ProgressRequestBody.ProgressCallback() {
          @Override
          public void onProgress(long progress, long total) {
              publishProgress(progress, total);
          }
      });

OkHttpClient client = new OkHttpClient.Builder() 
  .connectTimeout(10, TimeUnit.MINUTES) 
  .writeTimeout(10, TimeUnit.MINUTES) 
  .readTimeout(10, TimeUnit.MINUTES) 
  .build();
Request request = new Request.Builder()
  .header("X-Client-Type", "Android")
  .addHeader("APIKEY", "SomeRND")
  .url(url)
  .post(body)
  .build();

//Exception occures here:
Response response = client.newCall(request).execute();

ProgressRequestBody扩展了默认的okhttp RequestBody添加了一个用于报告当前uploadprogress的接口。 我覆盖了 writeTo(BufferedSink接收器) - 方法如下:

@Override
public void writeTo(BufferedSink sink) throws IOException {
    long fileLength = mUploadInfo.contentLength;
    byte[] buffer = new byte[65536];
    InputStream in = in();
    long uploaded = 0;

    try {
        int read;
        while((read = in.read(buffer)) != -1) {
            mListener.onProgress(uploaded, fileLength);
            uploaded += read;
            sink.write(buffer, 0, read);
        }
    } finally {
        in.close();
    }
}

通过 in() -method

读取文件
 private InputStream in() throws IOException {
        InputStream stream = null;

        try {
            stream = getContentResolver().openInputStream(mUploadInfo.contentUri);
        } catch (Exception ex) {
            Log.e(LOG_TAG, "Error getting input stream for upload", ex);
        }

        return stream;
  }

大约3-5分钟后上传失败。有人能告诉我如何获得稳定的连接或在它破碎后恢复吗?在几篇文章中,我读到ssl异常发生在大文件上传时并不罕见,但我发现没有令人满意的解决方案如何解决这个问题。

0 个答案:

没有答案