Java Android到PHP:epipe中断管道/流关闭使用httpurlconnection发布分块多部分表单数据

Java Android到PHP:epipe中断管道/流关闭使用httpurlconnection发布分块多部分表单数据,java,php,android,Java,Php,Android,我在使用HttpUrlConnection从android应用程序上传视频文件到服务器并使用PHP处理时遇到问题。通过发送一个多部分post请求,可以成功地对大小高达12mb的视频文件执行此操作,但对16mb的文件执行此操作失败,并出现内存不足错误 我试图通过使用setChunkedStreamingMode1024或SetFixedLength StreamingModeContentLength进行分块来解决内存不足错误。但是,这会导致错误,如epipe断裂管道和流关闭。我不知道该怎么处理

我在使用HttpUrlConnection从android应用程序上传视频文件到服务器并使用PHP处理时遇到问题。通过发送一个多部分post请求,可以成功地对大小高达12mb的视频文件执行此操作,但对16mb的文件执行此操作失败,并出现内存不足错误

我试图通过使用setChunkedStreamingMode1024或SetFixedLength StreamingModeContentLength进行分块来解决内存不足错误。但是,这会导致错误,如epipe断裂管道和流关闭。我不知道该怎么处理

我试过的

我第一次尝试使用Kevin Sawicki的,这导致了大文件的内存不足错误。当我实现分块或设置FixedLengthStreamingMode时,会导致epipe断管错误

异步任务中的Android代码:

日志:

然后我尝试只发送没有库的文件,代码来自,这导致流关闭错误

Android代码:

Logcat

问题 因此,我的问题是: 如何解决分块时连接/流关闭的问题

如果连接问题是由于服务器端问题造成的,我如何找出原因并解决它们?请注意,upload_max_文件大小为512M,因此大小不是问题所在。此外,12mb正常工作,16mb故障

我不确定如何使用PHP处理来自服务器的分块数据。对于在没有分块的情况下成功上传的12mb文件,我使用move_uploaded_file$_FILES['file']['tmp_name'],$url;处理得很好;。处理分块数据需要什么代码?

如上所述,如果正文长度事先已知,则应调用setFixedLengthStreamingModelen;如果正文长度未知,则应调用setChunkedStreamingMode0。 关于断管错误,请注意,如果可能的话,因为在移动环境中建立连接是一项消耗资源的操作。尝试通过新连接强制执行POST:请注意,android中的默认行为是将该头设置为true,您可以通过调用System.setPropertyhttp.keepAlive、false来更改它

如上所述,如果正文长度事先已知,则应调用setFixedLengthStreamingModelen;如果正文长度未知,则应调用setChunkedStreamingMode0。 conn.setRequestProperty("connection", "close"); // disables Keep Alive
关于断管错误,请注意,如果可能的话,因为在移动环境中建立连接是一项消耗资源的操作。尝试通过新连接强制执行POST:请注意,android中的默认行为是将该头设置为true,您可以通过调用System.setPropertyhttp.keepAlive、false来更改它

这可能是服务器端的最大文件大小限制。我认为调整服务器或php设置。您应该查看服务器端错误日志。如果PHP配置正确,它应该将错误记录到apache日志文件中,在PHP.ini文件中检查其配置,日志文件可能在服务器端的/var/log/apache或/var/log/httpd下。@greenapps,phpinfo表示上载的最大文件大小为512M,所以我认为上载大小没有问题。@realpoint,上述代码不会产生服务器记录的任何错误。我可以确认这一点,因为当应用程序向PHP服务器发送请求时,会记录其他错误。我猜请求根本没有到达服务器。嗨@bardi。文件大小似乎不像我想的那么重要。我尝试在启用setChunkedStreamingMode的情况下发送一个小jpeg文件,但也出现了错误,尽管在禁用分块时它仍然有效。这可能是服务器端的最大文件大小限制。我认为调整服务器或php设置。您应该查看服务器端错误日志。如果PHP配置正确,它应该将错误记录到apache日志文件中,在PHP.ini文件中检查其配置,日志文件可能在服务器端的/var/log/apache或/var/log/httpd下。@greenapps,phpinfo表示上载的最大文件大小为512M,所以我认为上载大小没有问题。@realpoint,上述代码不会产生服务器记录的任何错误。我可以确认这一点,因为当应用程序向PHP服务器发送请求时,会记录其他错误。我猜请求根本没有到达服务器。嗨@bardi。文件大小似乎不像我想的那么重要。我尝试在启用setChunkedStreamingMode的情况下发送一个小jpeg文件,但也出现了错误,尽管在禁用分块时它仍然有效。我想这是正确的答案,我遇到了类似的问题。使用它就是解决方案。我花了3天的时间来解决这个问题,我希望我能早点找到这个帖子。我想这是正确的答案,我正在处理一个类似的问题。我花了3天的时间来解决这个问题,我希望我能早点找到这篇文章。 conn.setRequestProperty("connection", "close"); // disables Keep Alive
HttpURLConnection conn = null;
DataOutputStream dos = null;
DataInputStream inStream = null;
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "***************************************************";
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 212144; // 1024*1024 = 1MB.  212144 is a quarter MB.
FileInputStream fileInputStream = null;

try {
    fileInputStream = new FileInputStream(videoFile);
    // open a URL connection to the Servlet
    URL url = new URL(postUrl);
    // Open a HTTP connection to the URL
    conn = (HttpURLConnection) url.openConnection();
    // Allow Inputs
    conn.setDoInput(true);
    // Allow Outputs
    conn.setDoOutput(true);
    // Send in chunks (to avoid out of memory error)
    conn.setChunkedStreamingMode(maxBufferSize); // results in stream closed error
    // Don't use a cached copy.
    conn.setUseCaches(false);
    // Use a post method.
    conn.setRequestMethod("POST"); 
    conn.setRequestProperty("Connection", "Keep-Alive");
    conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="
        + boundary);
    conn.setReadTimeout(200000); // 200 seconds...
    dos = new DataOutputStream(conn.getOutputStream());
    dos.writeBytes(twoHyphens + boundary + lineEnd);
    dos.writeBytes("Content-Disposition: form-data; name=\"file\";filename=\""
        + videoFile.getName() + "\"" + lineEnd);
    dos.writeBytes(lineEnd);
    // create a buffer of maximum size
    bytesAvailable = fileInputStream.available();
    bufferSize = Math.min(bytesAvailable, maxBufferSize);
    buffer = new byte[bufferSize];
    // read file and write it into form...
    bytesRead = fileInputStream.read(buffer, 0, bufferSize);
    while (bytesRead > 0)
    {
      try {
        dos.write(buffer, 0, bufferSize);          
      } catch (OutOfMemoryError oome) {
        Log.e(DEBUG_TAG, "Out of memory error caught...");
        oome.printStackTrace();
        fileInputStream.close();
        throw new Exception("Out Of Memory!");
      }
      bytesAvailable = fileInputStream.available();
      bufferSize = Math.min(bytesAvailable, maxBufferSize);
      bytesRead = fileInputStream.read(buffer, 0, bufferSize);
      // send multipart form data necesssary after file data...
      dos.writeBytes(lineEnd);
      dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
      fileInputStream.close();
      dos.flush();
      dos.close();

      // close streams
      Log.d(DEBUG_TAG, "Backup file written to server successfully...");
    }
} catch (Exception e) {
    // TODO: handle exception
    e.printStackTrace();
}
10-24 16:29:29.070: I/dalvikvm-heap(19832): Grow heap (frag case) to 23.474MB for 4147216-byte allocation
10-24 16:29:29.090: D/dalvikvm(19832): GC_FOR_ALLOC freed 1K, 20% free 22595K/28144K, paused 20ms, total 20ms
10-24 16:29:29.100: W/CursorWrapperInner(19832): Cursor finalized without prior close()
10-24 16:29:30.700: D/ProgressBar(19832): setProgress = 0
10-24 16:29:30.700: D/ProgressBar(19832): setProgress = 0, fromUser = false
10-24 16:29:30.700: D/ProgressBar(19832): mProgress = 0mIndeterminate = false, mMin = 0, mMax = 10000
10-24 16:29:30.770: D/CreateQuestion(19832): Backup file written to server successfully...
10-24 16:29:30.770: W/System.err(19832): java.io.IOException: stream closed
10-24 16:29:30.775: W/System.err(19832):    at libcore.net.http.AbstractHttpOutputStream.checkNotClosed(AbstractHttpOutputStream.java:37)
10-24 16:29:30.775: W/System.err(19832):    at libcore.net.http.ChunkedOutputStream.write(ChunkedOutputStream.java:65)
10-24 16:29:30.775: W/System.err(19832):    at java.io.DataOutputStream.write(DataOutputStream.java:98)
10-24 16:29:30.775: W/System.err(19832):    at com.example.askacademy.CreateQuestionActivity$createQuestionTask.doInBackground(CreateQuestionActivity.java:405)
10-24 16:29:30.775: W/System.err(19832):    at com.example.askacademy.CreateQuestionActivity$createQuestionTask.doInBackground(CreateQuestionActivity.java:1)
10-24 16:29:30.775: W/System.err(19832):    at android.os.AsyncTask$2.call(AsyncTask.java:287)
10-24 16:29:30.780: W/System.err(19832):    at java.util.concurrent.FutureTask.run(FutureTask.java:234)
10-24 16:29:30.780: W/System.err(19832):    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
10-24 16:29:30.780: W/System.err(19832):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
10-24 16:29:30.780: W/System.err(19832):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
10-24 16:29:30.780: W/System.err(19832):    at java.lang.Thread.run(Thread.java:841)
10-24 16:29:30.780: W/System.err(19832): org.json.JSONException: Unterminated object at character 52 of {"success":"false","error":"Error creating question"
10-24 16:29:30.780: W/System.err(19832):    at org.json.JSONTokener.syntaxError(JSONTokener.java:450)
10-24 16:29:30.780: W/System.err(19832):    at org.json.JSONTokener.readObject(JSONTokener.java:394)
10-24 16:29:30.780: W/System.err(19832):    at org.json.JSONTokener.nextValue(JSONTokener.java:100)
10-24 16:29:30.780: W/System.err(19832):    at org.json.JSONObject.<init>(JSONObject.java:154)
10-24 16:29:30.780: W/System.err(19832):    at org.json.JSONObject.<init>(JSONObject.java:171)
10-24 16:29:30.780: W/System.err(19832):    at com.example.askacademy.CreateQuestionActivity$createQuestionTask.doInBackground(CreateQuestionActivity.java:461)
10-24 16:29:30.780: W/System.err(19832):    at com.example.askacademy.CreateQuestionActivity$createQuestionTask.doInBackground(CreateQuestionActivity.java:1)
10-24 16:29:30.780: W/System.err(19832):    at android.os.AsyncTask$2.call(AsyncTask.java:287)
10-24 16:29:30.780: W/System.err(19832):    at java.util.concurrent.FutureTask.run(FutureTask.java:234)
10-24 16:29:30.780: W/System.err(19832):    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
10-24 16:29:30.780: W/System.err(19832):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
10-24 16:29:30.785: W/System.err(19832):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
10-24 16:29:30.785: W/System.err(19832):    at java.lang.Thread.run(Thread.java:841)
conn.setRequestProperty("connection", "close"); // disables Keep Alive