Первой версии флудера комментами мне показалось мало. Хотелось нечто большего, например флуд комментами в количестве тысячи сообщений чей-то паги за короткие сроки по времени. Как я уже сказал, в первой версии флудера имели место два недостатка:
1) Отсутствие поддержки
зарегистрированного пользователя для отправки комментов.
2) Отсутствие потоков, что сказывалось на времени и медлительности флудера.
Знание Перла и стремление повысить "рейтинг" флудера помогли мне написать вторую версию скрипта ljflood.pl, который поддерживал авторизацию и потомки. Углубимся в процесс кодинга и обработки потомков.
Сперва сделаем авторизацию. Для этого возьмем произвольную страничку с комментами для поста с номером... пусть будет 31337. Смотрим вид html и акцентируем внимание на авторизацию. Что мы видим? Нам нужно заполнить поля Username, который имеет имя userpost, поле для пароля (password) и установить радиобатон usertype в положение user (в первой версии он был anonymous).
Для минимального изменения кода, но с максимальной реализацией вышеописанного, немножко поправим наш скрипт.
Поставим условие перед строчкой $usertype='anonymous':
if ($opt_u) { $usertype='user'."&userpost=$opt_u"
."&password=$opt_p";
} else {
$usertype='anonymous';
}
предварительно добавив букву "u" в getopt() чуть выше.
Что мы получили? Если имеется параметр, указывающий имя пользователя, установим usertype равный части большого POST-запроса, включающий в себя
usertype, userpost и password. Иначе посылаем анонимные комменты.
Вот собственно и все. Первая задача была решена. Осталось добиться многопотоковости и вторая версия флудера была бы готова.
Для поддержки потоков в perl используется функция fork(), которая позволяет запустить подпроцесс в беграунд. Кроме того, нам необходимо контролировать количество этих самых подпроцессов, чтобы ненароком не уронить сервер, на котором запускается флудер ;).
Алгоритм такой: делаем постоянное количество треадов (потомков) равным, к примеру, 10. Затем делим количество комментов на 10 и берем целую часть от деления. Это нужно для реализации двойного цикла for() без лишних переменных. После этого
открываем внешний цикл по новому количеству комментов, а внутренний по треадам. Затем плодим потомок функцией fork, составляя массив @forked в теле родителя. В этом массиве будут хранится идентификаторы подпроцессов (зачем - поймешь чуть позже). В теле потомка, вызываем функцию sendcomment(), которая будет засылать коммент врагу =).
$count=$opt_c || 10; ## Забираем $count из параметра
$count=int($count/$threads); ## И делим нацело его на 10
for ($j=1;$j<=$count;$j++) { ## Внешний цикл по каунту
for ($i=1;$i<=$threads;$i++) { ## Внутренний по потомкам
if ($pid=fork()) { ## Плодим потомок с процессом $pid
push(@forked,$pid); ## Фиксируем идентификатор в массиве
} else {
sendcomment($i); ## Засылаем коммент
exit; ## И завершаем потомок - это важно!
}
}
killpidz(); ## Процедура убийства потомков.
}
После каждого выполнения внутреннего цикла переходим к процедуре killpidz(), которая будет убивать
не завершившиеся процессы, тем самым контролируя безопасную работу скрипта.
sub killpidz { ## Процедура убийства порожденных процессов
foreach $pid (@forked) {
chomp; ## По каждому процессу из списка
waitpid($pid,0); ## Дожидаемся его завершения
kill("TERM" => $_) ## А лишь затем убиваем его
}
}
Таким образом, после каждой прокрутки внутреннего цикла, будет происходить убийство потомков. Причем убивать скрипт будет потомки, которые завершили свою работу, гарантируя успешную отсылку коммента.
Осталось подфиксить процедуру usage(), в которой добавляется описание полей userpost и password для
наглядности скрипта. И все, задачи будут выполнены =). В тестировании скрипт показал себя с лучшей стороны, было успешно заслано 50 комментариев (ради теста я уменьшил количество треадов до 5) за сравнительно малое время (около 10 секунд). В итоге получаем вполне работоспособную версию флудера, которую ты можешь взять по адресу:
http://kamensk.net.ru/forb/1/ljflood2.tar.gz.