System.OutOfMemory客户端文件在服务器端的异常

本文关键字:服务器端 异常 文件 OutOfMemory 客户端 System | 更新日期: 2023-09-27 18:35:31

我正在从客户端获取数据并将其保存到本地主机上的本地驱动器。我已经检查了221MB的文件,但是对1Gb文件的测试给出了以下异常:

mscorlib 中发生了类型为"System.OutOfMemoryException"的未处理异常.dll

以下是服务器端出现异常的代码。

更新

服务器:

      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.Is 有任何异步方法,以帮助提供服务器端收到的文件的进度。

System.OutOfMemory客户端文件在服务器端的异常

将整个内容写入光盘之前,您无需将整个内容读取到内存中。只需直接从网络流复制到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);
}

请注意,不应显式调用netStream.Close(),而应使用 using 语句:

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 ,这将为您提供一种异步读取和写入的方法。

请注意从流中删除前四个字节的代码。这样做是为了避免将流的长度与"有效负载"字节一起写入。如果您可以控制网络协议,则可以更改发送端以停止使用其长度作为流的前缀,并删除在接收端读取和忽略它的代码。