簡體   English   中英

服務器端客戶端文件的System.OutOfMemoryException

[英]System.OutOfMemoryException on server side for client files

我正在從客戶端獲取數據並將其保存到本地主機上的本地驅動器中。我已經檢查了它是否為221MB的文件,但是對1Gb的文件進行的測試給出了以下異常:

mscorlib.dll中發生了'System.OutOfMemoryException'類型的未處理異常

以下是在服務器端產生異常的代碼。

更新

服務器:

      public void Thread()
        {
           TcpListener tcpListener = new TcpListener(ipaddr, port);
           tcpListener.Start();
           MessageBox.Show("Listening on port" + port);      
           TcpClient client=new TcpClient();
           int bufferSize = 1024;
           NetworkStream netStream;
           int bytesRead = 0;
           int allBytesRead = 0;

           // Start listening
           tcpListener.Start();

           // Accept client
           client = tcpListener.AcceptTcpClient();
           netStream = client.GetStream();

          // Read length of incoming data to reserver buffer for it
           byte[] length = new byte[4];
           bytesRead = netStream.Read(length, 0, 4);
           int dataLength = BitConverter.ToInt32(length,0);

         // Read the data
           int bytesLeft = dataLength;
           byte[] data = new byte[dataLength];

           while (bytesLeft > 0)
             {

                int nextPacketSize = (bytesLeft > bufferSize) ? bufferSize : bytesLeft;

                bytesRead = netStream.Read(data, allBytesRead, nextPacketSize);
                allBytesRead += bytesRead;
                bytesLeft -= bytesRead;

             }

           // Save  to desktop
           File.WriteAllBytes(@"D:\LALA\Miscellaneous\" + shortFileName, data);

          // Clean up
          netStream.Close();
          client.Close();

    }

我首先從客戶端獲取文件大小,然后再獲取數據。

1)。是否應該增加緩沖區大小或其他任何方法?

2)。 File.WriteAllBytes()File.ReadAllBytes()似乎阻塞並凍結了PC。是否有任何異步方法可幫助提供服務器端接收到的文件的進度。

您無需在將整個內容寫入光盤之前將其讀取到內存中。 只需直接從網絡流復制到FileStream

byte[] length = new byte[4];
// TODO: Validate that bytesRead is 4 after this... it's unlikely but *possible*
// that you might not read the whole length in one go.
bytesRead = netStream.Read(length, 0, 4);
int bytesLeft = BitConverter.ToInt32(length,0);

using (var output = File.Create(@"D:\Javed\Miscellaneous\" + shortFileName))
{
    netStream.CopyTo(output, bytesLeft);
}

請注意,您應該使用using語句,而不是顯式調用netStream.Close()

using (Stream netStream = ...)
{
    // Read from it
}

這樣,即使拋出異常,流也將關閉。

CLR的每個對象限制略微不足2GB。 但這是理論,實際上可以分配多少內存取決於框架允許分配的內存。 我不希望它允許您分配1 GB數據表。 您應該分配較小的表,並將數據分塊寫入磁盤文件。

之所以會發生“內存不足”異常,是因為您試圖在將整個文件轉儲到磁盤之前將其放置到內存中。 這不是最理想的,因為您不需要內存中的整個文件即可寫入文件:您可以以合理大小的增量逐塊讀取它,並隨即將其寫出。

從.NET 4.0開始,您可以使用Stream.CopyTo方法在幾行代碼中完成此操作:

// Read and ignore the initial four bytes of length from the stream
byte[] ignore = new byte[4];
int bytesRead = 0;
do {
    // This should complete in a single call, but the API requires you
    // to do it in a loop.
    bytesRead += netStream.Read(ignore, bytesRead, 4-bytesRead);
} while (bytesRead != 4);
// Copy the rest of the stream to a file
using (var fs = new FileStream(@"D:\Javed\Miscellaneous\" + shortFileName, FileMode.Create)) {
    netStream.CopyTo(fs);
}
netStream.Close();

從.NET 4.5開始,您也可以使用CopyToAsync ,這將為您提供一種異步進行讀寫的方法。

請注意從流中刪除前四個字節的代碼。 這樣做是為了避免將流的長度與“有效載荷”字節一起寫入。 如果您可以控制網絡協議,則可以更改發送方以停止為其長度加上流前綴,並刪除在接收方讀取和忽略它的代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM