Публикация файла в фоновом агенте / потоковом буфере HttpWebRequest продолжает расти? - PullRequest
1 голос
/ 12 марта 2012

Мне нужно POST файл 5 МБ из ResourceIntensiveTask, где ОС устанавливает максимальное использование памяти 5 МБ.Так что попытка потокового файла напрямую из хранилища, но поток, связанный с 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();
        }

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

Я также задаю AllowReadStreamBuffering = false для HttpWebRequest.

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

Ответы [ 2 ]

2 голосов
/ 26 марта 2012

Проблема в том, что, не имея возможности отключить буферизацию записи, соединение с сервером даже не устанавливается до тех пор, пока не будет вызвано 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 , чтобы это было возможно (см. это сообщение в блоге).

0 голосов
/ 23 марта 2012

Я заметил одну вещь: ты забыл утилизировать 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 var отсутствует, поэтому здесь остается ошибка кодирования!

...