[*] Ошибка кажется более распространенной с большим/большим изображением, но не всегда. Трассировка стека исключений может варьироваться, часто указывая на этап записи (например, в SocketOutputStream.socketWrite , вызываемой из My ConnectionHandler.transferfileto ) или фаза после записи/предварительного ответа (например, httpurlConnectionImpl.getResponsecode CodeShode
Различные тайм-ауты подключения и чтения. (Webmaster сообщает, что время считывания сервера составляет 30 секунд) />
Какие механизмы на стороне клиента могут привести к тому, что выходной поток httpurlconnection преждевременно сломается при написании многочисленного тела, особенно если содержимого мысли
< /ul>
- ByteArrayOutputStream (baos) Для тела и длины содержимого :
[*] baos.tobytearray () был записан в httpurlconnection sputstream . Матч тела, что приводит к неизменно успешной загрузке и ответе сервера.
[/list]
- различное число/размер изображений: с одним маленьким изображением до нескольких больших изображений. Массив изображений, отправляемых на сервер PHP.
- Обеспечение закрытия потока: используется try-with-resources для всех inputstream и outputstream , чтобы убедиться, что они правильно закрыты. Значения (15-30 секунд).
фактический результат (проблема): Вместо этого процесс загрузки весьма прерывист. Это исключение может возникнуть либо, казалось бы, во время написания мультитарного тела в outputStream , либо когда я позже пытаюсь вызвать conn.getResponsecode () .
[*] редко (ок. Основной проблемой является непредсказуемая «сломанная труба» и неспособность надежно заполнить передачу данных и получить ответ сервера, даже при использовании таких методов, как BAOS, которые должны обеспечить точность ..
prong> concectionhandler.java: соответствующий код - пожалуйста, запрашивайте больше, если необходимо p> p> p> p> p> p> p> p> p> p> p> p> p> p> p> p> p> p> p> p> p> p> p> p> p> p> p> p> p> p> prongehandler.// In ConnectionHandler.java
package com.example.authtest.Tools;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
// ... other necessary imports ...
public class ConnectionHandler {
private static final String TAG = "ConnectionHandler";
private static final String UPLOAD_URL_STRING = "REDACTED";
// Method called by CameraFragment
public void uploadImages(String serviceToken, String username, String jobNum, String maxFileSize, File[] images, boolean overviewShot, boolean checkingIn, String checkingInDate, UploadCallback callback) {
HttpURLConnection conn = null;
String boundary = "Boundary-" + System.currentTimeMillis(); // Unique boundary for each request
try {
// 1. Calculate Content-Length using a "dry run"
long contentLength = constructAndSendMultipartFormData(null, boundary, username, jobNum, maxFileSize, images, overviewShot, checkingIn, checkingInDate);
Log.d(TAG, "Calculated Content-Length: " + contentLength);
URL url = new URL("REDACTED");
URL conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(15000); // 15 seconds
conn.setReadTimeout(30000); // 30 seconds
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "close");
conn.setRequestProperty("Authorization", "REDACTED");
conn.setRequestProperty("Cookie", "REDACTED");
conn.setRequestProperty("User-Agent", "MyApp/1.0");
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
conn.setRequestProperty("Content-Length", Long.toString(contentLength));
conn.setDoOutput(true);
conn.setUseCaches(false);
// 2. Write the actual body
OutputStream os = null; // Declare os outside try to check if it was opened
try (OutputStream os = conn.getOutputStream()) {
constructAndSendMultipartFormData(os, boundary, username, jobNum, maxFileSize, images, overviewShot, checkingIn, checkingInDate);
os.flush();
} catch (IOException e) {
Log.e(TAG, "IOException during body write to REDACTED: " + e.getMessage(), e); // If "Broken pipe" happens here, it means connection dropped during write
callback.onUploadError(e);
return; // Don't proceed to getResponseCode
}
// 3. Get response
int responseCode = conn.getResponseCode(); // "Broken pipe" frequently occurs here if not during write Log.d(TAG, "Response Code from REDACTED: " + responseCode); // Logic to read response (success or error stream)
if (responseCode >= 200 && responseCode < 300) {
callback.onUploadComplete("Success - " + responseCode); // Provide more info if needed
} else {
callback.onUploadError(new IOException("Server at REDACTED returned HTTP error: " + responseCode));
}
} catch (IOException e) {
// General IOExceptions, including "Broken pipe" if it happens at getOutputStream() or getResponseCode()
Log.e(TAG, "General IOException during upload to REDACTED: " + e.getMessage(), e);
callback.onUploadError(e);
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
// Dual-purpose method: calculates length if outputStream is null, otherwise writes.
private long constructAndSendMultipartFormData(OutputStream outputStream, String boundary, String username, String jobNum, String maxFileSize, File[] images, boolean overviewShot, boolean checkingIn, String checkingInDate) throws IOException {
long totalLength = 0L; final String CRLF = "\r\n";
final byte[] CRLF_BYTES = CRLF.getBytes(StandardCharsets.UTF_8);
totalLength += writeFormField(outputStream, boundary, "username", username);
totalLength += writeFormField(outputStream, boundary, "jobNum", jobNum);
String usernamePartHeader = "--" + boundary + CRLF + "Content-Disposition: form-data; name=\"username\"" + CRLF + CRLF;
byte[] usernamePartHeaderBytes = usernamePartHeader.getBytes(StandardCharsets.UTF_8);
byte[] usernameBytes = username.getBytes(StandardCharsets.UTF_8);
totalLength += usernamePartHeaderBytes.length;
totalLength += usernameBytes.length;
totalLength += CRLF_BYTES.length;
if (outputStream != null) {
outputStream.write(usernamePartHeaderBytes);
outputStream.write(usernameBytes);
outputStream.write(CRLF_BYTES);
}
String overviewShotStr = overviewShot ? "1" : "0";
String overviewShotHeader = "--" + boundary + CRLF + "Content-Disposition: form-data; name=\"overviewShot\"" + CRLF + CRLF;
byte[] overviewShotHeaderBytes = overviewShotHeader.getBytes(StandardCharsets.UTF_8); byte[] overviewShotBytes = overviewShotStr.getBytes(StandardCharsets.UTF_8);
totalLength += overviewShotHeaderBytes.length + overviewShotBytes.length + CRLF_BYTES.length;
if (outputStream != null) {
outputStream.write(overviewShotHeaderBytes);
outputStream.write(overviewShotBytes);
outputStream.write(CRLF_BYTES);
}
// Image files
if (images != null) {
for (File imageFile : images) {
if (imageFile == null || !imageFile.exists() || imageFile.length() == 0) {
Log.w(TAG, "Skipping invalid or empty image file: " + (imageFile != null ? imageFile.getName() : "null file"));
continue;
}
String fieldNameInForm = "technicianPictures";
String originalFileName = imageFile.getName();
String filePartHeader = "--" + boundary + CRLF + "Content-Disposition: form-data; name=\"" + fieldNameInForm + "\"; filename=\"" + originalFileName + "\"" + CRLF + "Content-Type: image/jpeg" + CRLF + // Assuming JPEG, make dynamic if other types
"Content-Transfer-Encoding: binary" + CRLF + // Optional, usually implied for files
CRLF; // Empty line before file data
byte[] filePartHeaderBytes = filePartHeader.getBytes(StandardCharsets.UTF_8);
totalLength += filePartHeaderBytes.length;
if (outputStream != null) {
outputStream.write(filePartHeaderBytes);
}
long fileLength = transferFileTo(imageFile, outputStream);
totalLength += fileLength; // CRLF after file data
totalLength += CRLF_BYTES.length;
if (outputStream != null) {
outputStream.write(CRLF_BYTES);
}
}
}
// End boundary: --boundary--CRLF
String endBoundaryStr = "--" + boundary + "--" + CRLF;
byte[] endBoundaryBytes = endBoundaryStr.getBytes(StandardCharsets.UTF_8);
totalLength += endBoundaryBytes.length;
if (outputStream != null) {
outputStream.write(endBoundaryBytes);
}
return totalLength;
}
// Dual-purpose file transfer: returns length if outStream is null, otherwise writes.
private long transferFileTo(File file, OutputStream outStream) throws IOException {
if (outStream == null) {
// Calculate length only
if (!file.isFile()) return 0L;
return file.length();
}
// Write mode
long writtenLength = 0L;
if(file.isFile()) {
try (FileInputStream fis = new FileInputStream(file)) {
byte[] buffer = new byte[4096]; // Common buffer size
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead); // "Broken pipe" can occur here during the stream
writtenLength += bytesRead;
}
}
}
Log.d(TAG, "Transferred " + writtenLength + " bytes for file " + file.getName());
return writtenLength;
}
// Callback interface for upload status
public interface UploadCallback {
void onUploadComplete(String response);
void onUploadError(Exception e);
}
}
< /code>
camerafragment.java: соответствующий код - пожалуйста, попросите больше, если необходимо < /strong> < /li>
< /ul>
// In CameraFragment.java
// ... (Initializes File[] capturedImages and imageCount) ...
// Inside an upload button's OnClickListener:
// ... (Code to get user credentials, job details, etc., as Strings) ...
String authToken = ...;
String currentUsername = ...;
String currentJobNumber = ...;
String maxFileSizeAllowed = ...; // e.g., "10485760"
File[] imagesToUploadArray = new File[imageCount];
if (imageCount > 0) {
System.arraycopy(capturedImages, 0, imagesToUploadArray, 0, imageCount);
}
new Thread(() -> {
try { // Simplified call to ConnectionHandler
connectionHandler.uploadImages(authToken, currentUsername, currentJobNumber, maxFileSizeAllowed, imagesToUploadArray, isOverviewShot, isCheckingIn, checkingInDate, new ConnectionHandler.UploadCallback() {
@Override public void onUploadComplete(String response) {
// Update UI: Upload successful
Log.d("CameraFragment", "Upload successful: " + response);
}
@Override
public void onUploadError(Exception e) {
// Update UI: Upload failed
Log.e("CameraFragment", "Upload error reported by callback", e);
// This is where the "Broken pipe" or other IOExceptions often land
}
});
} catch (Exception e) {
Log.e("CameraFragment", "Exception launching upload thread", e);
}
}).start();
Подробнее здесь: https://stackoverflow.com/questions/797 ... ltipart-up
Мобильная версия