我有一个应用程序,该应用程序从TCP连接的现场接收GPRS客户端的数据。GPRS客户端设备不时将失去连接并缓冲数据,恢复连接后,所有缓冲数据都发送到TCP连接,从而引起我的应用程序以投掷系统。
我认为这是因为接收到的数据大于我的缓冲区大小(设置为int.maxvalue)。
- 如何防止我的应用程序用完存储器?
- 我如何确保我不会丢失任何不在的数据?
以下是用于收听的代码,并处理Incomming Data
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);
}
}
}
关于缓冲器
OutOfMemoryException
s当没有顺序存储器左时抛出。
就您而言,这意味着connection.ReceiveBufferSize
太大,无法在一件方面保持记忆力。不是因为收到的数据大于您的缓冲区大小。
您可以使用较小的,固定的缓冲区获取接收的字节,将其附加在某个地方,然后使用相同的缓冲区接收其余数据,直到拥有所有数据为止。
要注意的一件事是您用于存储收到数据的集合。例如,您不能使用 List<byte>
,因为它将其元素存储在引擎盖下的一个阵列中,这比一口气一起来没有区别 - 就像您现在一样。
您可以看到Memory Tributary,这是用于替换MemoryStream
的流实现。您可以将其流将其复制到该流并将其保存为流。此页面还包含许多信息,可以帮助您了解OutOfMemoryException
s。
此外,我写了一位缓冲区经理,以提供固定尺寸的缓冲区。您可以在这里的代码评论中找到。
关于线程
为创建每个连接的线程野蛮。它们的价格为1 MB,因此您应该使用ThreadPool
或更好的IOCP(通过Socket
类的异步方法)。
您可能想研究这些有关插座编程的常见陷阱和最佳实践:
- Stephen Cleary(博客)|TCP/IP .NET插座FAQ
- 堆栈溢出|如何编写基于TCP/IP的可扩展服务器
- 代码项目|C#socketAsynceventargs高性能套接字代码
使用固定的接收缓冲区,然后逐步解析