在TCP连接上接收大量数据时出现内存不足异常

时间:2012-11-03 06:56:34

标签: c# networking tcp stream

我有一个应用程序,它通过TCP连接从现场的GPRS客户端接收数据。 GPRS客户端设备不时丢失连接并缓冲数据,当连接恢复时,所有缓冲的数据都被发送到TCP连接,告诫我的应用程序抛出System.OutOfMemoryException。

我认为这是因为收到的数据大于我的缓冲区大小(设置为int.MaxValue)。

  1. 如何阻止我的应用程序内存不足?
  2. 如何确保我不会丢失任何输入数据?
  3. 以下是用于监听和处理数据的代码

    public void Listen(string ip, int port)
    {
        _logger.Debug("All.Tms.SensorDataServer : SensorDataListener : Listen");
    
        try
        {
            var listener = new TcpListener(IPAddress.Parse(ip), port);
            listener.Start();
    
            while (true)
            {
                var client = listener.AcceptTcpClient();
                client.SendBufferSize = int.MaxValue;
    
                var thread = new Thread(() => ReadAndHandleIncommingData(client));
                thread.IsBackground = true;
                thread.Start();
            }
        }
        catch (Exception ex)
        {
            _logger.Error("TMS.Sensor.SensorDataServer : SensorDataListener : Error : ", ex);
        }  
    }
    

    private void ReadAndHandleIncommingData(TcpClient connection)
    {
         try
         {
             var stream = connection.GetStream();
             var data = new byte[connection.ReceiveBufferSize];
    
             var bytesRead = stream.Read(data, 0, System.Convert.ToInt32(connection.ReceiveBufferSize));
    
             var sensorDataMapper = new SensorDataMapperProvider().Get(data);
    
             if (sensorDataMapper != null)
             {
                 _sensorDataHandler.Handle(sensorDataMapper.Map(data));
             }
        }
        catch (Exception ex)
        {
            _logger.Error("TMS.Sensor.SensorDataServer : SensorDataListener : ReadAndHandleIncommingData : Error : ", ex);
        }
        finally
        {
            try
            {
                connection.Close();
            }
            catch(Exception ex)
            {
                _logger.Error("All.Tms.SensorDataServer : SensorDataListener : ReadAndHandleIncommingData : Error : ", ex);
            }
        }
    }
    

2 个答案:

答案 0 :(得分:4)

关于缓冲区

当没有顺序记忆时,会抛出

OutOfMemoryException 在您的情况下,这意味着connection.ReceiveBufferSize太大而无法保存在一个内存中。不是因为收到的数据大于缓冲区大小

您可以使用较小的固定缓冲区来获取接收到的字节,将其附加到某处并使用相同的缓冲区来接收其余数据,直到您拥有它为止。

需要注意的一件事是用于存储接收数据的集合。例如,你不能使用List<byte>因为它将它的元素存储在引擎盖下的单个数组中,这与一次性完成所有操作没有区别 - 就像你现在一样。

您可以看到MemoryTributary,一个用于替换MemoryStream的流实现。您可以将流复制到此流并将其保存为流。此页面还包含大量可帮助您了解OutOfMemoryException的原因的信息。

此外,我写了一个缓冲管理器,以提供固定大小的缓冲区。您可以在代码审核中找到here

关于帖子

每个连接创建一个线程残酷。它们每个花费1 MB,因此您应该使用ThreadPool或更好的IOCP(通过Socket类的异步方法)。

您可能希望了解有关套接字编程的常见缺陷和最佳实践:

答案 1 :(得分:2)

使用固定的接收缓冲区,并逐步解析数据