Общая структура В основе системы закачки файлов находится база данных (MySQL v5.1). Основное её предназначение – хранение очереди закачек. Помещение новых объектов в эту очередь происходит через интерфейсную часть, в качестве которой я выбрал сервис ICQ. Непосредственно закачку осуществляет скрипт ddd.pl, выбирающий из базы данных информацию об очередном скачиваемом объекте. Вся система закачки базируется на ОС FreeBSD 6.2. Каким же функционалом будет наделена наша система закачек? Каждый из закачиваемых объектов имеет приоритет (значения от 0 до 255, где 255 – наивысший приоритет), в соответствии с которым демон ddd.pl будет осуществлять выборку из БД очередного объекта скачивания. Я говорю об объектах скачивания, потому как система закачек в моей реализации поддерживает ftp и http ссылки и достаточно просто расширяема для работы с другими протоколами. Далее, желательно, чтобы система закачек не занимала весь канал под свои нужны, поэтому необходимо встроить средства ограничения скорости передачи данных (на основе DUMMYNET). Закачка файлов будет происходить под пользователем icq_bot (входящего в группу nobody), а скаченные файлы будут размещаться в /home/icq_bot/allfiles/. Файрвол будет ограничивать скорость передачи данных для всех процессов пользователя icq_bot. Рассмотрим реализацию. Конфигурирование ядра Для работы системы закачки достаточно добавить в ядро следующие опции: options IPFIREWALL # активизировать ipfw options DUMMYNET # активизировать поддержку пайпов и очередей Пересоберем ядро и приступим к конфигурированию полученной операционной системы. Конфигурирование FreeBSD Для начала активизируем запуск скрипта /etc/rc.firewall при загрузке системы. Для этого добавим следующую строку в файл /etc/rc.conf: firewall_enable=YES Для того чтобы появилась возможность ограничения скорости закачек добавим следующее правило файервола: /sbin/ipfw pipe 1 config bw 64Kbit/s /sbin/ipfw add 5000 pipe 1 ip from any to me uid icq_bot В последнем добавленном правиле мы ограничиваем скорость только у процессов, выполняемых под пользователем icq_bot. Создадим в домашней директории пользователя icq_bot директорию allfiles: cd /home/icq_bot && mkdir allfiles chown icq_bot:nobody allfiles В эту директорию впоследствии будут помещаться все скачанные файлы. База данных ICQ интерфейс Для работы по протоколу ICQ были найдены модули Net::ICQ2000 и Net::OSCAR . Было решено остановиться на последнем – его программный интерфейс более прост. Помимо этого NET::OSCAR есть в портах: cd /usr/ports/net-im/p5-Net-OSCAR make install Рассмотрим сокращенный вариант кода ICQ бота (icq_bot.pl): Code: #!/usr/bin/perl use Net::OSCAR; use DBI; # конфигурационные данные $MAX_SPEED=512; $DB_NAME="icq_bot"; $DB_HOST="localhost"; $DB_USER="user"; $DB_PASS="pass"; # UIN администратора бота $ADM_UIN=999999999; # хеш, содержащий имена команд и связанные с ними функции %functions = ("speed" =>\&speed, "htftp" => \&htftp, "showlist" => \&showlist, "del" => \&del, "chgprior" => \&chgprior); # подключение к ICQ серверу $oscar = Net::OSCAR->new(); # функция-обработчик входящих сообщений $oscar->set_callback_im_in(\&message_callback); # здесь поместите свой UIN и пароль $oscar->signon(666666, "passpasspass") or die("Авторизация не удалась!\n"); # бесконечный цикл $quit = 0; while(!$quit) { $oscar->do_one_loop(); } # # ядро бота # sub message_callback { local($cmd, $params, $result); local $result = ""; local($client, $uin, $msg) = @_; $ADM_UIN=new Net::OSCAR::Screenname $ADM_UIN; # разрешаем управление ботом только с UIN`а $ADM_UIN return if($uin ne $ADM_UIN); # получаем имя команды(с префиксом “!”) и её параметры if(($cmd, $params) = $msg =~ /^\!([^\ ]+)\s*(.*)$/) { local $dbh=DBI->connect("DBI:mysql:$DB_NAME:$DB_HOST", $DB_USER, $DB_PASS, {RaiseError => 1}); # такая обработка ошибок сократит код работы с БД # и сделает его более наглядным eval {$result = exists($functions{$cmd}) ? $functions{$cmd}($params) : ""}; if($@) {$result="Error: $@";} $client->send_im($uin, $result) if $result; $dbh->disconnect(); } } # функция регулировки скорости в % sub speed { my ($result, $cmd, $speed); my $request=$_[0]; # определяем скорость: $speed=int($request*$MAX_SPEED/100); # изменяем значение пропускной скорости канала 1: $cmd="/sbin/ipfw pipe 1 config bw ".$speed."Kbit/s"; system($cmd) ; $result=`/sbin/ipfw pipe show 1 | head -1`; return $result; } # добавляем новую задачу в очередь закачек sub htftp { # аргументы функции – ссылка и необязательное # значение приоритета её закачки my ($link, $prior)=split(/ /, $_[0]); my $result; $prior=int($prior); my $sql="INSERT INTO download_queue (add_time, type, link, prior) VALUES (NOW(), 'htftp', '$link', $prior)"; $dbh->do($sql); return "Link added!"; } # функция отображения очереди закачек sub showlist { my ($query, $id, $add_time, $link, $prior, $result); # задания находятся в состоянии ожидания, если не # установлено время начала и окончания закачки $query=$dbh->prepare("SELECT id, add_time, link, prior FROM download_queue WHERE start_time IS NULL AND end_time IS NULL ORDER BY prior DESC, add_time"); $query->execute(); while(($id, $add_time, $link, $prior)= $query->fetchrow_array()) { $result.="$id\t$add_time\t$link\t$prior\n" } $result.="Queue is empty!" if($result==''); return $result; } Полученный скрипт разместим в директории /usr/local/bin и назначим ему право на исполнение: chmod +x /usr/local/bin/icq_bot.pl Если у вас есть желание «демонизовать» этот скрипт, то добавьте следующий строки: Code: use POSIX; # «клонируем» себя $pid=fork; exit if $pid; die "Ошибка fork: $!" unless defined($pid); # в порожденном процессе переназначаем # дескрипторы ввода/вывода/ошибок for my $handle (*STDIN, *STDOUT, *STDERR) { open($handle, "+<", "/dev/null"); } POSIX::setsid(); # назначаем собственный обработчик функций: $SIG{INT}=$SIG{TERM}=$SIG{HUP}=\&softexit; sub softexit { # мягкое завершение ICQ сессии $oscar->signoff(); $quit=1; } Вызов «демонизированного» скрипта разместим в файле rc.local: echo “/usr/local/bin/icq_bot.pl”>>/etc/rc.local Запустим полученный код и добавим нашего ICQ-бота себе в контакт лист: Бот обрабатывает команды только с UIN`а, заданного в переменной $ADM_UIN. Кодом определено, что бот обрабатывает все строки, предваренные символом «!». Испытаем на нем команды: Скрипт закачек Code: #!/usr/bin/perl use DBI; # конфигурационные данные $DB_NAME="icq_bot"; $DB_HOST="localhost"; $DB_USER="user"; $DB_PASS="pass"; $WGET_PATH="/usr/local/bin/wget"; # функции закачки вызываются через хеш # (по аналогии с кодом icq_bot.pl) %functions = ("htftp" => \&htftp); $quit = 0; my ($id, $type, $link); my $dbh=DBI->connect("DBI:mysql:$DB_NAME:$DB_HOST", $DB_USER, $DB_PASS, {RaiseError => 1}); # Continue downloading; while(!$quit) { eval { # выбираем очередной элемент из очереди my $sql="SELECT id, type, link FROM download_queue WHERE start_time IS NULL AND end_time IS NULL ORDER BY prior DESC, add_time LIMIT 1"; my $query=$dbh->prepare($sql); $query->execute(); if($query->rows>0) { ($id, $type, $link)=$query->fetchrow_array(); print "Starting download $id $link $type"; # делаем запись в БД о времени начала закачки $sql="UPDATE download_queue SET start_time=NOW() WHERE id=$id"; $dbh->do($sql); # вызываем функцию-обработчик для закачек типа $type $functions{$type}($link); $sql="UPDATE download_queue SET end_time=NOW() WHERE id=$id"; $dbh->do($sql); return; } # если очередь пуста, # то проверяем её каждые 10 секунд `sleep 10`; }; if($@) { print "Error: $@\n"; } } #end of main body $dbh->disconnect(); # обработчик http и ftp закачек sub htftp { my $link=@_[0]; my $cmd="$WGET_PATH -c $link"; print $cmd; system("$cmd"); exit $? if($?); } Подобно icq_bot.pl, можно «демонизировать» этот скрипт, но я решил поступить иначе – привязать вывод скрипта ddd.pl к виртуальному терминалу ttyv7, который вызывается нажатием комбинации клавиш Alt+F8. Для начала разместим скрипт ddd.pl в домашней директории пользователя icq_bot. Там же создадим небольшой скрипт startddd.sh (не забудьте назначить ему права на исполнение): #!/bin/sh sudo -u icq_bot /home/icq_bot/ddd.pl Далее, в файле /etc/gettytab добавим строки, описывающие новый тип терминала: icqbot:ht:np:sp#115200:al=icq_bot:lo=/home/icq_bot/startddd.sh: Здесь мы переопределили программу авто загрузки (по умолчанию /usr/bin/login) на наш скрипт. Осталось переопределить тип седьмого виртульного терминала. Для этого в файле /etc/ttys добавим параметр icqbot к вызову getty: ttyv7 "/usr/libexec/getty icqbot" cons25r on secure Все готово: kill -1 1 Заключение Предложенная мной система, как и любая другая, не идеальна, но имеет некоторый запас для дальнейшего развития: * наращивание числа протоколов, с которыми она может работать * повышение отказоусточивости * более гибкая приоритезация * управление временем закачек Расширенную версию icq_bot.pl и ddd.pl вы можете скачать отсюда: //Автор: Ostretsov Atrem rufog@mail.ru
На вид канает под дипломный проэкт но ИМХО ИЗВРАТ. 1. Нафига база данных, можно обойтись текстовым файлом. 2. я юзаю прогу на Делфи + пхп-скрипт, который отвечает за список закачки. Конечно, подписать под это icq - весело. например, качается список а если что-то срочное то по аське скинуть но все таки это лишнее палево. Легче вставить строку в файл в нужное место.