- Подписка на печатную версию:
- Подписка на электронную версию:
- Подшивки старых номеров журнала (печатные версии)
LXF100-101:Программирование на Perl
Материал из Linuxformat.
Программирование |
---|
|
Содержание |
Программирование: личный IRC-бот
- ЧАСТЬ 1: Любите покодировать, но нет свежих идей? Майк Сондерс затевает серию публикаций о полезных мини-программах. Начнем с персонального IRC-бота…
Добро пожаловать в новую серию публикаций о программировании. В трех статьях этого цикла мы покажем, как писать полезные программы, а затем расширять и улучшать их по мере роста вашего умения. Ключевое слово здесь – «программа»: мы не будем копаться ни в теории, ни в сугубо техническом мусоре; вместо этого рассмотрим классные штуки, которые можно вытворять в различных языках программирования. Ведь гораздо интереснее писать настоящую программу, чем тратить время на изучение нудных конструкций циклов! А если вы уже пробовали кодировать, проблем с пониманием у вас не возникнет.
IRC (Internet Relay Chat - ретранслируемый интернет-чат) - это система обмена сообщениями в режиме реального времени, предшественница всемирной паутины (World Wide Web), изобретенная в 1988 году. IRC - открытый текстовый протокол, и написать клиента для него может каждый. IRC-обсуждения проходят в нескольких сетях; одни ориентированы на свободное ПО (irc://irc.freenode.net), а другие - на игры.
Каждая IRC-сеть состоит из нескольких серверов, связанных друг с другом - можно выбрать как ближайший к вам географически, так и любой другой случайным образом. В любом случае вы будете частью одной и той же сети. Например, чтобы начать общаться в сети Freenode, найдите IRC-клиент (например, X-Chat), запустите его и введите:
/server irc.freenode.net
(команды IRC начинаются со слэша). После этого зарегистрируйте имя пользователя и пароль с помощью следующих команд:
/nick <mynickname> /msg nickserv register <mypassword>
Потом можно зайти в «канал» (отдельная комната чата) с помощью команды:
/join #linuxformat
(Название канала начинается с символа решетки.) Теперь можете писать сообщения в общий чат или приватные сообщения отдельным пользователям (например, в X-Chat для этого кликните правой кнопкой на имени пользователя и выберите в меню «Открыть диа- лог»).
Начнем с IRC-бота, написанного на Perl. Если вы интернетчик со стажем, то наверняка пользовались IRC; если нет – прочтите врезку «Стоп… а что такое IRC?», там объясняются базовые понятия. Коротко говоря, IRC – это чат в реальном времени, часто используемый разработчиками открытого ПО для взаимодействия друг с другом. Он очень быстр, в нем легко разобраться, и – главное – можно создавать виртуальных участников чата.
Этим мы и займемся – напишем «робота», который присоединяется к чату и рассказывает о компьютере. Скажем, вы на работе или в отпуске далеко от дома и хотите наблюдать за домашней системой (или за сервером на площадке провайдера). Наш IRC-бот будет сидеть себе в чате и ждать, когда появитесь вы и спросите его о времени работы системы и ее загрузке.
При выборе IRC-клиента глаза разбежались? Пользователи Linux избалованы выбором!
Не страшно! В журнале под номером 97 мы испытывали восемь лучших: KVIrc, Konversation, Kopete, XChat, Pidgin, Chatzilla, Opera и Irssi прошлись перед нами строем ради определения победителя.
Программ для мониторинга системы немеряно, но они страдают повышенной дотошностью и забивают ваш почтовый ящик письмами с лишними подробностями о работе компьютера. С нашим ботом все намного проще: если вы хотите узнать, сколько осталось свободного места на диске, или посмотреть, хватает ли оперативной памяти, просто заскочите в IRC и спросите у него (через приватные сообщения). А самое важное – мы ограничим доступ так, чтобы эти данные могли получить только вы!
Букварь на Perl
Для начала пройдемся по основам Perl. Вы, небось, подумали: «А с какой стати писать этого бота на Perl?» Хороший вопрос. Ведь Perl – это язык скриптов, изначально задуманный для обработки текста. Однако он также снабжен массой модулей расширения, один из которых существенно упрощает взаимодействие с серверами IRC.
Perl сейчас предустановлен почти в каждом дистрибутиве; если в вашей системе его не оказалось, он почти наверняка найдется в менеджере пакетов. Это интерпретируемый язык, поддерживающий объектно-ориентированный подход и динамическую типизацию (то есть не нужно ни заранее объявлять переменные, ни задавать их тип). Последующие фрагменты кода набирать не надо: просто уясните, как они работают. Вывод строки элементарен:
print “Привет!”;
Все выражения завершаются точкой с запятой (;), в стиле языка C. Имена переменных начинаются со знака доллара:
$num = 25; $string = “гамбургеров”; print “Я съел $num $string\n”;
Как видите, Perl не задумывается о типах переменных – он определяет их на лету. Аналогично C, символ \n означат перевод строки. Массивы объявляются с символом @:
@distros = (“Ubuntu”, “Fedora”, “SUSE”); print $distros[0];
Этот код выводит на экран слово “Ubuntu”. По принципу многих других языков программирования, первый элемент массива получает номер 0. Для массивов полезна команда shift – она удаляет первый элемент массива и помещает его в переменную:
@distros = (“Ubuntu”, “Fedora”, “SUSE”); $foo = shift(@distros); print “$foo\n”; $foo = shift(@distros); print “$foo\n”;
Мы создали массив из трех строк, затем сдвинули (shift) его первый элемент в переменную $foo, вывели ее и сдвинули массив еще раз. Итак, сначала выводится строка “Ubuntu”, за ней – “Fedora”, и в итоге в массиве остался единственный элемент, “SUSE”. Расширенная версия массива – это «словарь» (или «хэш»), объявление которого начинается со знака процента (%):
%weight = (“Mike” => 8, “Paul” => 12, “Nick” => 25);
Здесь список слов связывается со значениями. Например, вы хотите вывести вес (weight) записи Nick:
print $weight{“Nick”};
Выведется 25. if устроен точно так же, как в большинстве других языков:
$x = 64; if ($x == 64) { print “Yep, x is 64!\n”; }
И, наконец, подпрограммы (функции) объявляются просто командой sub:
sub saystuff { print “This is saystuff!\n”; } saystuff();
Таковы «колесики и винтики» программирования на Perl – все, что нам нужно, чтобы начать писать IRC-бота!
Установка
Масса возможностей модуля Net::IRC осталась за рамками этого обзора - просмотрите файлы .pm в архиве, чтобы узнать о них больше. Также рассмотрите другой пример реализации бота, скрипт в файле irctest.
Воспользуемся специальным модулем расширения языка Perl Net::IRC, предоставляющим интерфейс для протокола IRC – тогда нам не придется писать тонны кода для работы с сокетами и соединениями. Вместо этого мы попросим Net::IRC позаботиться о сетевых взаимодействиях, а сами будем дрессировать бота: пусть делает то, что нам нужно.
Вы можете найти Net::IRC с помощью своего менеджера пакетов (он называется perl-irc или net.pm или как-то вроде этого). А не найдете, не беда: собрать его из исходных текстов проще простого [даже термин «собрать» здесь избыточен: Net::IRC написан на Perl, так что речь идет просто о копировании его в нужный каталог, – прим.ред.]. Зайдите на сайт http://search.cpan.org/dist/Net-IRC/ или откройте раздел Development/Net-IRC нашего DVD (первая сторона) и скопируйте файл Net-IRC-0.75.tar.gz.
Распакуйте архив, зайдите в образовавшийся каталог и введите команды:
perl Makefile.PL make make install
Последнюю из них нужно выполнять с правами администратора. Она установит модуль Net::IRC, и программа, которую мы напишем, сможет его применить!
Далее создадим две учетных записи для IRC: первая – для вас, вторая – для бота (если вы завсегдатай IRC, то первая у вас уже есть). Это важный этап, поскольку из-за борьбы со спамом на многих IRC-серверах пользователь должен зарегистрироваться, чтобы иметь возможность отправлять приватные сообщения другим участникам чата.
Зайдите в IRC и переключитесь в вашего обычного пользователя. Если вы еще не зарегистрированы, введите такую команду:
/msg nickserv register <password>
(<password> замените на подходящий пароль). Примеры команд приведены для серверов Freenode, в других сетях они могут отличаться. Теперь ваш пользователь зарегистрирован на сервере IRC – то есть никто другой это имя не отберет. Сказать IRC-серверу, кто вы такой, можно с помощью команды:
/msg nickserv identify <password>
Нужно также зарегистрировать как пользователя нашего, пока нерожденного, бота. Переключитесь в другого пользователя и задайте ему пароль таким образом:
/nick UltraCoolLXFBot /msg nickserv register thisismypassword
Конечно, можно взять другое имя пользователя и пароль, но запомните их, ведь они понадобятся коду нашего бота! Итак, мы завели две зарегистрированные учетные записи, себе и боту.
Покажи мне код
Мы готовы к запуску бота. Вот его код. Его не придется набирать вручную: он приведен на нашем DVD в разделе Magazine/Perl (файл bot1.pl). Но прежде чем запускать бота, не мешает просмотреть код и его описание...
use Net::IRC; $server = ‘irc.freenode.net’; $channel = ‘#blergh’; $botnick = ‘MegaMikeBot’; $password = ‘foobar’; $botadmin = ‘M-Saunders’; $irc = new Net::IRC; $conn = $irc->newconn(Nick => $botnick, Server => $server, Port => 6667); $conn->add_global_handler(‘376’, \&on_connect); $conn->add_global_handler(‘disconnect’, \&on_disconnect); $conn->add_global_handler(‘kick’, \&on_kick); $conn->add_global_handler(‘msg’, \&on_msg); $irc->start; sub on_connect { $self = shift; $self->privmsg(‘nickserv’, “identify $password”); $self->join($channel); $self->privmsg($channel, “Lo! I’m just a silent bot.”); } sub on_disconnect { $self = shift; $self->connect(); } sub on_kick { $self = shift; $self->join($channel); $self->privmsg($channel, “Please don’t kick me!”); } sub on_msg { $self = shift; $self->privmsg($botadmin, `uptime`); }
Давайте пройдемся по коду. Первая строка просто сообщает интерпретатору Perl, что мы хотим использовать ранее установленную библиотеку Net::IRC. На пяти следующих строках объявляются параметры конфигурации – перед запуском скрипта их потребуется изменить. Мы определяем адрес IRC-сервера, с которым соединится наш бот, и канал, в который он войдет; затем задаем имя пользователя (ник) и пароль, с помощью которых бот авторизуется на IRC-сервере. Наконец, задается имя пользователя, с которым бот будет говорить – ваша обычная учетная запись IRC.
После этого в строке $irc = new Net::IRC; создается объект IRC-бота, с творчески выбранным именем $irc. Затем мы формируем объект $conn, который создает соединение с IRC-сервером на основе предоставленной ранее информации. Итак, на данном этапе у бота есть все необходимое для подключения к IRC-серверу.
Но сперва нужно сделать еще одну вещь: связать с сообщениями, которые бот получает от IRC-сервера, некоторые действия. Наш бот ведь не глухонемой, и он должен знать, на какие сообщения давать ответ. Четыре вызова add_global_handler об этом позаботятся – они говорят боту: «Получив сообщение А, перейди к подпрограмме B».
Например, первая строка этого куска кода говорит: «Если получим сообщение 376, вызываем функцию on_connect». Сообщение 376 – специальный код, возвращаемый IRC-сервером на стадии установки соединения: сервер доставил информацию, что связь успешно установлена, и готов к приему команд. Если вы любитель посидеть в IRC, то знаете, что во время установки соединения на экране появляется множество сообщений о статусе сервера, сообщений данного сообщества и т.д. Код 376 означает конец приветствий.
Далее следуют обработчики еще для трех событий: разрыв соединения, удаление из чата и приватное сообщение. Обработчики говорят боту, какие функции вызвать в тех случаях, когда связь прекращается, бота гонят из чата или он получает приватное сообщение соответственно. IRC-боты могут реагировать и на всякие другие сообщения, но для нашего случая этого достаточно.
Команда $irc->start; приводит бота в действие. Бот обучен, какой сервер и канал использовать и какие подпрограммы вызывать при получении определенных сообщений; он соединяется с сервером и через несколько секунд получает сообщение 376, о котором мы говорили ранее. Оно активирует функцию on_connect.
В этой функции вы увидите команду shift, которая была описана в разделе с примером на Perl. Можете не вникать в суть кода, вкратце скажем, что он делает: аргументы передаются функции в массиве, и первый из них – вызывающий объект. Значение первого аргумента, вызывающий объект, присваивается переменной $self, тогда можно будет вызывать его функции. Есть и другие варианты, но наш обеспечивает модульность кода.
После соединения бота с сервером мы отправляем приватное сообщение (privmsg) nickserv – это обработчик имени пользователя на большинстве серверов IRC. Мы предоставляем пароль бота для аутентификации его на сервере. Затем мы заходим в заданный канал и отправляем небольшое сообщение, означающее, что мы будем вести себя тихо, не засоряя канал всяким хламом!
Теперь бот будет смирно сидеть в канале, пока его оттуда не пнут или не прервется соединение. В этих случаях он вызовет соответствующие функции и кротко попросит: «Пожалуйста, не удаляйте меня» (“Please don’t kick me!”) или повторно создаст соединение. Самая важная функция здесь – это on_msg. Она вызывается, когда бот получает приватное сообщение – то есть сообщение в отдельном диалоге вне основного канала. В ответ на любое сообщение бот отправляет вывод команды `uptime` пользователю $botadmin, т.е. вашему обычному пользователю.
Обратите внимание на обратные одиночные кавычки (`) вокруг команды `uptime`. Они велят Perl выполнить указанную команду [в оболочке, – прим.ред.] и вернуть результат в виде строки. Таким образом, строка с privmsg отправляет нашему пользователю приватное сообщение, содержащее вывод команды uptime. На большинстве клавиатур клавиша одиночной обратной кавычки находится под клавишей Escape.
Продолжаем работать
Пора запустить бота. Откройте файл bot1.pl и измените пять конфигурационных переменных сверху в соответствии с вашими настройками – а именно, впишите имя пользователя и пароль для бота, вами зарегистрированные, а свое имя пользователя присвойте переменной $botadmin. Запустите IRC-клиента, авторизуйтесь на сервере и зайдите в канал, который вы указали для бота. Затем запустите бота:
perl bot1.pl
Через пару секунд бот установит соединение, авторизуется на сервере и зайдет в указанный канал. Вы узнаете о его появлении по небольшому приветствию! Командой privmsg начните приватный диалог с ботом и скажите ему все, что угодно – бот пришлет результат выполнения команды uptime. Отлично! Теперь можно запустить бота на любом компьютере и отслеживать время работы системы (и уровни загрузки), просто общаясь с ботом в IRC-чате.
Хотя нарекания остаются. Кто бы ни заговорил с ботом в приватном канале, результат выполнения команды uptime отправится вам. Бот также умеет выполнять только команду uptime – может, вам этого и достаточно, но он способен на гораздо большее.
Если все работает нормально, можно добавить в последнюю функцию (on_msg) новые возможности, например, таким образом (полный код бота – в файле bot2.pl на DVD):
sub on_msg { $self = shift; $event = shift; if ($event->nick eq $botadmin) { foreach $arg ($event->args) { if ($arg =~ m/uptime/) { @output = 'uptime'; foreach $line (@output) { $self->privmsg($botadmin, $line); } } if ($arg =~ m/df/) { @output = 'df'; foreach $line (@output) { $self->privmsg($botadmin, $line); } } } } }
На этот раз мы проверяем (if), кто отправляет боту приватное сообщение (третья строка), и продолжим только если это $botadmin, то есть вы! Посмотрим на текст, отправленный боту. Он содержится в массиве $event->args.
Пройдемся по тексту и выясним, есть ли там команда, подлежащая выполнению. Этим занимается строка if ($arg =~ m/uptime/): она означает «Если одна из строк текста, отправленного боту, содержит строку uptime, сделай следующее...» Фрагмент m/uptime/ – регулярное выражение, проверяющее, есть ли в тексте строка uptime.
Если она есть, запустим команду uptime и запишем результат ее выполнения в массив @output. Потом в цикле выведем каждую строку текста, содержащегося в массиве.
Uptime возвращает только одну строку текста – может, не стоит связываться с циклом? Но в следующем фрагменте кода проверяется, отправили ли мы команду df – а df возвращает несколько строк. Получив команду df, бот копит ее результат и отсылает его нам, строка за строкой.
Добавляйте новые команды, сколько душа просит. Для этого копируйте и вставляйте блок кода с if, а в нем меняйте текст, который там проверяется, и выполняемую команду. Например, можно добавить блок if ($arg =~ m/ps/), который получает список процессов с помощью команды @output = `ps`;. Можно вставить любую команду – бот все слопает!
Теперь у нас есть расширяемый IRC-бот, который отвечает на ваши команды и только вам. Он ни о чем не проболтается случайному посетителю (если только тот не зайдет под вашим именем и паролем). Вряд ли вы захотите разрешить боту выключать компьютер, но с его помощью можно получить о компьютере массу информации.
Написали своего бота с помощью этой статьи? Расскажите нам об этом: отправьте свой код по адресу letters@linuxformat.ru, и воз- можно, мы поместим его на LXFDVD. Если не удается заставить бота работать, загляните на наши форумы http://unixforum.org
Это очень гибкое решение: если кажется, что с компьютером что-то случилось, можно запустить бота на web-сервере и допросить его; или – запустить бота на домашнем компьютере и прямо с работы запускать и останавливать с его помощью определенные процессы. Возможности безграничны – а всего-то нужен доступ к IRC!