1

Мне нужно ПОСЛАТЬ 5 МБ-файл из ResourceIntensiveTask, где ОС устанавливает максимальное использование памяти 5 МБ. Так пытаясь передать поток прямо из хранилища, но поток, связанный с HttpWebRequest, продолжает расти. Это код:Проводка файла в буфере фонового агента/HttpWebRequest продолжает расти?

 public void writeStream(Stream writer, string filesource, string filename) 
     { 
      var store = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication(); 
      var f = store.OpenFile(filesource, FileMode.Open, FileAccess.Read); 
      store.Dispose(); 

      byte[] buffer = Encoding.UTF8.GetBytes(String.Format(@"Content-Disposition: form-data; name=""file""; filename=""{0}""\n", filename)); 
      writer.Write(buffer, 0, buffer.Length); 

      buffer = Encoding.UTF8.GetBytes("Content-Type: application/octet-stream\n"); 
      writer.Write(buffer, 0, buffer.Length); 

      long initialMemory = Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage; 

      buffer = new byte[2048]; 
      int DataRead = 0; 
      do 
      { 
       DataRead = f.Read(buffer, 0, 2048); 
       if (DataRead > 0) 
       { 
        writer.Write(buffer, 0, DataRead); 
        Array.Clear(buffer, 0, 2048); 
       } 
      } while (DataRead > 0); 

      double increasedMemory = ((double)Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage - initialMemory)/1000000;     

      buffer = Encoding.UTF8.GetBytes("\n--" + boundary + "\n--"); 
      writer.Write(buffer, 0, buffer.Length); 
      writer.Flush(); 
     } 

increasedMemory переменной отладки используются для получения дифференциальной памяти до и после того, как файл для чтения и передается на HttpWebRequest, и это дает почти точный размер файла (5 МБ) что означает, что память процесса увеличивается на 5 МБ.

Я также устанавливаю AllowReadStreamBuffering = false для HttpWebRequest.

Как сохранить память на низком уровне? Как загрузить большие файлы, когда ограничение использования памяти составляет 5 МБ?

+0

У меня такая же проблема - «OutOfMemoryException» при загрузке больших файлов (но из приложения переднего плана). Может, кто-то может помочь. Начал 'bounty' – Ku6opr

+0

Просто догадаться в этот момент (я не тестировал это), но вы пытались добавить' writer.Flush(); 'после' writer.Write() 'в цикле? – Nomad101

+0

Да. Кроме того, попробовал «Thread.Sleep» в цикле дождаться загрузки данных – Ku6opr

ответ

0

Одна вещь, которую я заметил: вы забыли распорядиться f!

лично я хотел бы использовать такой код:

public void writeStream(Stream writer, string filesource, string filename) 
{ 
    using (var store = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication()) 
    { 
     long initialMemory = Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage; 

     using (var f = store.OpenFile(filesource, FileMode.Open, FileAccess.Read)) 
     { 
      byte[] buffer = Encoding.UTF8.GetBytes(string.Format(@"Content-Disposition: form-data; name=""file""; filename=""{0}""\n", filename)); 
      writer.Write(buffer, 0, buffer.Length); 

      buffer = Encoding.UTF8.GetBytes("Content-Type: application/octet-stream\n"); 
      writer.Write(buffer, 0, buffer.Length); 

      buffer = new byte[2048]; 
      int DataRead = 0; 

      do 
      { 
       DataRead = f.Read(buffer, 0, 2048); 
       if (DataRead > 0) 
       { 
        writer.Write(buffer, 0, DataRead); 
       } 
      } while (DataRead > 0); 

      buffer = Encoding.UTF8.GetBytes("\n--" + boundary + "\n--"); 
      writer.Write(buffer, 0, buffer.Length); 
      writer.Flush(); 
     } 

     double increasedMemory = ((double)Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage - initialMemory)/1000000; 
    } 
} 

boundary вар, кажется, отсутствует, поэтому ошибка кодирования по-прежнему остается здесь!

+0

Проблема в' AllowWriteStreamBuffering', которая отсутствует в WP7 в «HttpWebRequest» и не имеет смысла в «WebClient». Поэтому внутренний 'MemoryStream' занимает размер всех данных, которые необходимо записать. – Ku6opr

+0

Совершенно верно, пропустил эту часть! –

+0

Да, код работает нормально на переднем плане, а также работает нормально, если DEBUGGER подключен (потому что это игнорирует ограничение памяти). Кто-нибудь смог это решить? – Jandieg

2

Проблема заключается в том, что, не будучи в состоянии отключить буферизацию записи, соединение с сервером даже не выполняется до тех пор, пока не будет вызван BeginGetResponse() после закрытия потока запросов (проверен с помощью WireShark).

Единственный способ, с помощью которого я могу обойти это, - это напрямую использовать сокеты (хотя это будет сложнее при использовании SSL-соединения).

Этот код работает для меня и не увеличивает использование памяти при отправке данных на сервер. Я не тестировал его в фоновом задании, но не вижу причин, чтобы он не работал.

Socket _socket; 
const int BUFFERSIZE = 4096; 
byte[] writebuffer = new byte[BUFFERSIZE]; 
string hostName = "www.testdomain.com"; 
string hostPath = "/test/testupload.aspx"; 
IsolatedStorageFileStream isoFile; 


public void SocketPOST(string hostName, string filesource) 
{ 
    using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) 
    { 
     if (store.FileExists(filesource)) 
     { 
      isoFile = store.OpenFile(filesource, FileMode.Open, FileAccess.Read); 
     } 
    } 

    _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
    _socket.SetNetworkRequirement(NetworkSelectionCharacteristics.NonCellular); 

    SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs(); 
    socketEventArg.RemoteEndPoint = new DnsEndPoint(hostName, 80); 
    socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(Socket_Completed); 

    _socket.ConnectAsync(socketEventArg); 
} 


private void Socket_Completed(object sender, SocketAsyncEventArgs e) 
{ 
    if (e.SocketError == SocketError.Success) 
    { 
     switch (e.LastOperation) 
     { 
      case SocketAsyncOperation.Connect: // Connected so started sending data, headers first 

       if (e.ConnectSocket.Connected) 
       { 
        StringBuilder sbHeaders = new StringBuilder("POST " + hostPath + " HTTP/1.1\r\n"); 
        sbHeaders.Append("HOST: " + hostName + "\r\n"); 
        sbHeaders.Append("USER-AGENT: MyWP7App/1.0\r\n"); 
        sbHeaders.Append("Content-Type: text/plain; charset=\"utf-8\"\r\n"); 
        sbHeaders.Append("Content-Length: " + isoFile.Length.ToString() + "\r\n\r\n"); 

        byte[] headerBuffer = Encoding.UTF8.GetBytes(sbHeaders.ToString()); 
        e.SetBuffer(headerBuffer, 0, headerBuffer.Length); 

        if (!e.ConnectSocket.SendAsync(e)) Socket_Completed(e.ConnectSocket, e); 
       } 

       break; 

      case SocketAsyncOperation.Send: 
      case SocketAsyncOperation.SendTo: // Previous buffer sent so send next one if stream not finished 

       Array.Clear(writebuffer, 0, BUFFERSIZE); 

       int DataRead = 0; 

       DataRead = isoFile.Read(writebuffer, 0, BUFFERSIZE); 
       if (DataRead > 0) 
       { 
        e.SetBuffer(writebuffer, 0, DataRead); 
        if (!_socket.SendAsync(e)) Socket_Completed(e.ConnectSocket, e); 
       } 
       else 
       { 
        isoFile.Dispose(); 
        if (!_socket.ReceiveAsync(e)) Socket_Completed(e.ConnectSocket, e); 
       } 

       break; 

      case SocketAsyncOperation.Receive: 
      case SocketAsyncOperation.ReceiveFrom: 

       if (e.BytesTransferred > 0) 
       { 
        string response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred).Trim('\0'); 

        // Check response if necessary 

        e.ConnectSocket.Shutdown(SocketShutdown.Both); 
        e.ConnectSocket.Dispose(); 
       } 

       break; 

      default: 
       break; 
     } 

    } 
} 

Примечание: Я оставил много в обработке, чтобы сделать пример короче ошибки.

SSL Примечания: Поскольку SSL работает на уровне TCP и WP7 пока не поддерживает SSL сокетов (SslStream), вам нужно будет обрабатывать рукопожатия сертификата, шифр обмен и т.д. самостоятельно, чтобы настроить соединение SSL на сокет, а затем шифровать все, что отправляется (и расшифровывать все полученные) с помощью согласованных алгоритмов. Был достигнут определенный успех с использованием API Bouncy Castle, чтобы это было возможно (см. Сообщение this).

+0

Очень интересно ... Недостатком ошибки является то, что он не будет работать под блокировкой экрана. :( – Ku6opr

+0

Правда, я помню ваш предыдущий пост об этой проблеме. Знаете ли вы, что это влияет и на фоновые агенты (сокет не работает в режиме блокировки)? – Nomad101

+0

«Фоновые агенты» - это не то же самое, что работает под блокировкой экрана :). Я думаю, что для этого нет никаких ограничений, и этот код должен гладко работать с «Фоновые агенты» – Ku6opr