我正在制作服务器而且我注意到它有一些奇怪的内存泄漏。在我的服务器上,我限制了一个IP地址可以达到8的总连接数。这非常有效。
然而,当我使用LOIC来操作我的服务器时,我注意到虽然它只创建了8个网络类实例,但StreamReader的ReadLine方法占用了很大一部分内存。
我已经使用Console.WriteLine验证了实际上没有收到任何数据,它只是等待该方法。内存增加并填满了我的整个16GB。
请注意,这个类中只有8个实例来自一个IP而且我正在做,而不是DDoS,它只来自我的IP(我已经验证了这一点)。
此问题的原因是什么?我该如何解决?
编辑:
相关代码是:
string data;
Dictionary<string, string> variables = null;
try {
while (_listen) {
data = null;
while ((data = _reader.ReadLine()) != null) {
答案 0 :(得分:0)
ReadLine
函数会将数据缓冲到一个字符串,它会遇到\r\n
(\n
单独就不会这样做)。它使用StringBuilder
。因此,如果您收到的数据不包含序列\r\n
,那么它最终会为单个字符串分配大量内存。
这里有一个简单的解决方案:您必须限制服务器愿意读取的最大字符串长度。这是处理恶意数据所必需的 - 如果您的服务器可能是DoS攻击的受害者,则永远不要相信您收到的数据。
所以,解决方案,作为TextReader
扩展方法:
public static String ReadLineSafe(this TextReader reader, int maxLength)
{
var sb = new StringBuilder();
while (true) {
int ch = reader.Read();
if (ch == -1) break;
if (ch == '\r' || ch == '\n')
{
if (ch == '\r' && reader.Peek() == '\n') reader.Read();
return sb.ToString();
}
sb.Append((char)ch);
// Safety net here
if (sb.Length > maxLength)
throw new InvalidOperationException("Line is too long");
}
if (sb.Length > 0) return sb.ToString();
return null;
}
这是原始ReadLine
代码,添加了安全检查。
哦,你应该将你的NetworkStream
包裹在BufferedStream
中以进行网络阅读,以避免在每个字节上调用recv
。