1

OS が 5MB の最大メモリ使用量を設定する ResourceIntensiveTask 内から 5MB のファイルを POST する必要があります。そのため、ファイルをストレージから直接ストリーミングしようとしていますが、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();
        }

incrementalMemory デバッグ変数は、ファイルが読み取られて HttpWebRequest にストリーミングされる前後の差分メモリを取得するために使用され、ファイルのほぼ正確なサイズ (5MB) を示します。これは、プロセス メモリが 5MB 増加していることを意味します。

また、 AllowReadStreamBuffering = false をHttpWebRequestに設定しています。

メモリを低く保つ方法は?メモリ使用量の上限が 5MB の場合に大きなファイルをアップロードするにはどうすればよいですか?

4

2 に答える 2

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 接続を設定し、すべてを暗号化する必要があります。合意されたアルゴリズムを使用して送信 (および受信したすべての暗号化を解除) します。Bouncy Castle APIを使用してある程度の成功を収めているため、それが可能になる可能性があります (このブログ投稿を参照してください)。

于 2012-03-26T11:57:13.990 に答える
0

私が気づいたことの1つは、あなたが破棄するのを忘れていたこと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;
    }
}

var が欠落しているboundaryように見えるため、コーディング エラーがまだここに残っています。

于 2012-03-23T17:03:03.437 に答える