且970 2024-11-23 22:14 采纳率: 0%
浏览 49
已结题

使用okhttp分片上传文件,报错:java.net.SocketException: Broken pipe

使用okhttp分片上传文件,报错:java.net.SocketException: Broken pipe,java.net.ProtocolException: unexpected end of stream

img


    private void UploadFile(String id, String name, long chunkSize, long size, Uri uri) {
        CHUNK_SIZE = chunkSize;
        OkHttpClient client = new OkHttpClient().newBuilder()
                .callTimeout(3000, TimeUnit.MILLISECONDS)
                .connectTimeout(3000, TimeUnit.MILLISECONDS)
                .readTimeout(3000, TimeUnit.MILLISECONDS).build();
        ContentResolver contentResolver = requireActivity().getContentResolver();
        try {
            InputStream inputStream = contentResolver.openInputStream(uri);
            if (inputStream == null) {
                throw new IOException("Failed to open input stream for URI: " + uri);
            }
            long fileSize = contentResolver.openFileDescriptor(uri, "r").getStatSize();
            long offset = 0;
            int chunkIndex = 0; // 分片编号从0开始
            while (offset < fileSize) {
                long chunk_Size = Math.min(CHUNK_SIZE, fileSize - offset);
                RequestBody requestBody = new ChunkedRequestBody(inputStream, offset, (int) chunk_Size);
                String uploadUrl = NasUrl.FILE_UPLOAD + "/" + id + "/" + chunkIndex; // 构建上传URL
                Log.e(TAG, "UploadFile: 分片大小:" + chunk_Size);
                Log.e(TAG, "UploadFile: 请求地址:" + uploadUrl);
                Request request = new Request.Builder()
                        .url(uploadUrl)
                        .method("POST", requestBody)
                        .header("Accept", "application/json, text/plain, */*")
                        .header("content-type", "application/octet-stream")
                        .build();
                client.newCall(request).enqueue(new Callback() {
                    @Override
                    public void onFailure(@NonNull Call call, @NonNull IOException e) {
                        Log.e(TAG, "UploadFile: 请求后:" + e);
                    }

                    @Override
                    public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                        Log.e(TAG, "UploadFile: 后台返回:" + response.body().string());
                    }
                });
//                try (Response response = client.newCall(request).execute()) {
//                    if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
//                    Log.d("Upload", response.body().string());
//                }
                offset += chunk_Size;
                chunkIndex++; // 准备上传下一个分片
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static class ChunkedRequestBody extends RequestBody {
        private final InputStream inputStream;
        private final long offset;
        private final int byteCount;

        ChunkedRequestBody(InputStream inputStream, long offset, int byteCount) {
            this.inputStream = inputStream;
            this.offset = offset;
            this.byteCount = byteCount;
        }

        @Override
        public MediaType contentType() {
            return MediaType.parse("application/octet-stream");
        }

        @Override
        public long contentLength() {
            return byteCount;
        }

        @Override
        public void writeTo(BufferedSink sink) throws IOException {
            inputStream.skip(offset);
            byte[] buffer = new byte[8192];
            int bytesRead;
            long bytesRemaining = byteCount;
            while (bytesRemaining > 0 && (bytesRead = inputStream.read(buffer, 0, (int) Math.min(buffer.length, bytesRemaining))) != -1) {
                sink.write(buffer, 0, bytesRead);
                bytesRemaining -= bytesRead;
            }
        }
    }
  • 写回答

11条回答 默认 最新

  • 阿里嘎多学长 2024-11-23 22:14
    关注

    阿里嘎多学长整理AIGC生成,因移动端显示问题导致当前答案未能完全显示,请使用PC端查看更加详细的解答过程

    问题分析

    该问题是使用 OkHttp 分片上传文件时,报错 java.net.SocketException: Broken pipejava.net.ProtocolException: unexpected end of stream

    解决方案

    1. 首先,我们需要检查 OkHttp 客户端的超时时间设置是否正确。可以尝试增加超时时间,特别是 connectTimeoutreadTimeout
    2. 其次,我们需要检查上传文件的流是否已经关闭。在 ChunkedRequestBody 类中,我们使用 skip 方法跳过了文件的 offset 分量,但是如果文件流已经关闭,那么读取文件流时将会抛出 SocketException: Broken pipe error。
    3. 最后,我们可以尝试使用 OkHttpClientnewCall 方法的 streaming 参数来启用流传输,这样可以避免文件流关闭的问题。

    代码修改

    OkHttpClient client = new OkHttpClient().newBuilder()
            .callTimeout(3000, TimeUnit.MILLISECONDS)
            .connectTimeout(3000, TimeUnit.MILLISECONDS)
            .readTimeout(3000, TimeUnit.MILLISECONDS)
            .build();
    
    // ...
    
    Request request = new Request.Builder()
            .url(uploadUrl)
            .method("POST", requestBody)
            .header("Accept", "application/json, text/plain, */*")
            .header("content-type", "application/octet-stream")
            .streaming(true) // Enable streaming
            .build();
    

    如果以上解决方案仍然无法解决问题,可以尝试在 ChunkedRequestBody 类中增加一些错误处理逻辑,以便捕捉文件流关闭的错误。

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 11月23日
  • 创建了问题 11月23日