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 有任何异步方法,以帮助提供服务器端收到的文件的进度。
将整个内容写入光盘之前,您无需将整个内容读取到内存中。只需直接从网络流复制到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
,这将为您提供一种异步读取和写入的方法。
请注意从流中删除前四个字节的代码。这样做是为了避免将流的长度与"有效负载"字节一起写入。如果您可以控制网络协议,则可以更改发送端以停止使用其长度作为流的前缀,并删除在接收端读取和忽略它的代码。