#c# #memory #tcpclient #tcplistener
#c# #память #tcpclient #tcplistener
Вопрос:
Я создаю сервер, и я заметил, что у него немного странная утечка памяти. На моем сервере я ограничил общее количество подключений, которые может сделать один IP-адрес, до 8. Это работает отлично.
Однако, когда я использую LOIC для DoS моего сервера, я замечаю, что, хотя он создает только 8 экземпляров сетевого класса, метод ReadLine StreamReader занимает большую часть памяти.
Я проверил с помощью консоли.WriteLine, что данные фактически не принимаются, он просто ожидает этого метода. И память увеличивается и заполняет все мои 16 ГБ.
Просто чтобы отметить, существует только 8 экземпляров этого класса с одного IP-адреса, и поскольку я использую Dos’ing, а не DDoS’ing, он всегда поступает только с моего IP-адреса (я проверил это).
В чем причина этой проблемы и как я могу ее исправить?
РЕДАКТИРОВАТЬ:
соответствующий код:
string data;
Dictionary<string, string> variables = null;
try {
while (_listen) {
data = null;
while ((data = _reader.ReadLine()) != null) {
Комментарии:
1. Если вы не отправите новую строку (
rn
), строка будет продолжать увеличиваться2. @LucasTrzesniewski Я не выбираю, что отправляется. Это DoS-атака, которую я запускаю против своего сервера.
3. Я знаю, это было только объяснение того, почему вещь потребляет память. Я подразумевал, что вам не следует использовать
ReadLine
, если вы заботитесь о DoS-атаках.4. А, хорошо, спасибо. Что бы вы порекомендовали?
5. Я напишу ответ.
Ответ №1:
ReadLine
Функция будет буферизовать данные в строку, пока не встретит a rn
( n
самостоятельно этого не сделает). StringBuilder
Для этого используется a . Итак, если полученные вами данные не содержат последовательности rn
, в конечном итоге будет выделено много памяти для одной строки.
Здесь у вас есть одно простое решение: вы должны ограничить максимальную длину строки, которую ваш сервер готов читать. Это необходимо для работы с вредоносными данными — никогда не доверяйте получаемым данным, если ваш сервер может стать жертвой 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' amp;amp; 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
для чтения netowrk, чтобы избежать вызова recv
каждого байта.
Комментарии:
1. Просто быстрый вопрос. Что делать, если длина получаемых данных непредсказуема. Допустим, у меня есть пользовательский тип в описании, если бы я указал 512 в качестве максимальной длины, прочитал бы он все 2048 байт данных?
2. В зависимости от вашего варианта использования вам придется подумать о том, какой разумный верхний предел для данных, которые вы ожидаете получить. Например, пользователь вряд ли введет в поле текст размером 1 МБ. Затем добавьте некоторый запас прочности и используйте это. Но ограничения, которые вы должны установить, зависят от конкретного приложения. Приведенная выше функция не будет считывать больше
maxLength
символов.3. Хорошо, спасибо. Я буду использовать этот код. Я отмечу это как ответ, если он будет работать нормально.
4. Я попробовал этот метод, и вместо того, чтобы просто замедлять работу моего компьютера и заполнять память, он фактически выводит его из строя. Может ли это быть вызвано этим методом?
5. Игнорируйте мой предыдущий комментарий, это была ошибка в моем коде, а не в вашем. Отлично работает, это исправило утечку памяти. Спасибо