Контакты

Для связи с нами можно использовать:
irc://irc.chatnet.ru:#gfs
icq://546460
email://cobalt[@]gfs-team.ru

Все материалы предоставлены только с ознакомительной целью
ГлавнаяСтатьиКодингPerl. IRC бот
© Cobalt 18.05.2006 статья не оптимизирована

Скачать исходники

 В этой статье мы попытаемся охотиться сразу на двух зайцев. А именно, разберем
IRC протокол и напишем скрипт на Perl, который будет выполнять функции IRC бота.
Эта статья посвящена в первую очередь програмистам которые хотят изучить Perl,
и подразумевается что они хотябы знают синтаксис данного языка.

 Для начала опишем настроечные переменные, а именно:
 
 1. Адрес и порт сервера.
 2. Ник и идент
 3. IRC канал на котором будет крутиться наш бот.
 
 Это делается так:
 
 $host="irc.lxxl.info";
 $port="6667";
 $nick="MyBot";
 $ident="MyBot";
 $chan="#GFS";
 
 Советую использовать в качестве сервера именно irc.lxxl.info, он не очень строг
к вашему иденту ). Далее создадим сокет соединения с сервером:

 use Socket;
 socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname(\'tcp\'))
     or die "Couldn`t create socket : $!\n";
 $iaddr=inet_aton($host);
 $paddr=sockaddr_in($port,$iaddr);
 print "\n>> Connecting to $host:$port...\n";
 connect(SOCK, $paddr)
     or die "Couldn`t connect to $host:$port : $!\n";
 for($i=0; $i<4; $i++){
  $data=;
  print($data);
 }
 
 Рассмотрим этот кусок кода более подробно. use Socket - сдесь мы указали что
необходимо использовать стандартную библиотеку Socket, которая содержит
функции и переменные для работы с сокетами. Функция socket предназначена
для создания сокета. В ее первом параметре указывается идентификатор по которому
мы в последствии будем обращаться к сокету. Во втором указывается комуникацион-
ный домен, в нашем случае это PF_INET, что означает домен Интернет. Так же
существует домен unix - PF_UNIX. Третий параметр указывает тип сокета. Мы будем
использовать SOCK_STREAM - этот тип обеспечивает последовательный, надежный
поток байтов. Так же существуют Datagram socket и Raw socket, но о них как-
нибудь в другой раз. И наконец в последнем параметре определяется протокол.
Делается это функцией getprotobyname(\'tcp\'), которая указывает в качестве
протокола TCP. Так же возможно использовать и udp, ip и т.д. Функция
getprotobyname возвращает название протокола в более удобном для функции socket
виде.

  Далее необходимо преобразовать адрес сервера в бинарную последовательность.
Для этого используется функция inet_aton(). И дописать в нее порт к которому
мы будем соединяться функцией sockaddr_in(). Теперь соединим сокет с сервером
функцией connect(). Если все прошло успешно, в указателе SOCK у нас будет
поток сокета. Работать с ним можно точно также как и с потоком файла. Например
при успешном соединении сервер должен послать нам четыре строки служебной инфы.
Вот мы их прочитаем и выведем на экран в цикле For.

 Теперь необходимо послать серверу информацию о себе. А именно идент и ник.
Для этого нам понадобится вункция send() которая принимает в качестве аргумента
три параметра: идентификатор сокета, строку которую необходимо отослать и 0.
Вместо нуля могут быть установлены следующие флаги:

  MSG_OOB       - Посылать/получать данные, характерные для сокетов типа
                  SOCK_STREAM
  MSG_DONTROUTE - Посылать данные без маршрутизации пакетов. Как правило
                  используется диагностическими программами и процессами
                  управляющими таблицами маршрутизации.

 Посылаем данные, читаем 10 строк и выводим на экран:
  
 print ">> Sending NICK and IDENT...\n";
 send (SOCK, "NICK $nick\n", 0);
 send (SOCK, "USER $ident localhost localhost :$nick\n", 0);
 for($i=0; $i<10; $i++){
  $data=;
  print($data);
 }
 
 В соответствии со стандартом IRC протокола, мы обязаны при соединении
уведомить сервер о том кто мы такие. Это делают IRC команды NICK и USER. Их
синтаксис не сложно понять из запросов которые мы только что отослали серверу.
Команда JOIN предназначается для входа на какой-либо канал. Отсылаем

 print ">> Join chanel $chan...\n";
 send (SOCK, "JOIN $chan\n", 0);

 для входа на указаный канал. Заметь, что каждая IRC команда оканчивается
обязательным символом \n (перенос строки). Ведь ты нажимешь Enter в mIRC ?=)
Давай запустим бесконечный цикл приема сообщений:

 while($data=){
  print($data);
 }
 close(SOCK);
 
 Теперь твой бот висит на канале и слушает что ему говорят. В окошке консоли
отлично видно какая информация приходит с сервера. Но возникает одна существен-
ная проблема: нашего бота через некоторое время выкидывает с сервера по таймауту
Это происходит из-за того что бот не отвичает на пинги посылаемые сервером.
Да да, на сервере установлен миханизм защиты от зомби. Каждому своему клиенту
через определенное время посылается команда PING, на которую в течении 256-ти
секунд клиент обязан ответить командой PONG с копией переданых данных. Если
же сервер по прошествии 256-ти секунд не получает ответа, он закрывает свое
соединение с клиентом, считая его зависшим.

 Выходом из данной ситуации будет служить если мы пропишем в цикле бота обработ-
чик пингов.Т.е. нам необходимо уловить когда придет комада содержащая слово PING
взять данные пришедшие вместе с ней, и отослать в месте с командой PONG обратно
серверу.

  @part=split(/:/,$data);
  if(@part[0] eq "PING "){
    print ">> PONG :@part[1]\n";
    send (SOCK, "PONG :@part[1]\n", 0);
  }
  
 Функция split разбирает строку в переменную, считая в качестве разделителя
первый аргумент. В нашем случае это простейшее регулярное выражение /:/, которое
указывает в качестве разделителя двоеточие. После у нас в массиве @part
содержатся элементы строки $data. eq - аналогично знаку равенства для
строк.

 Теперь было бы не плохо если бы наш бот хоть что-то бы делал, а не просто сидел
и молчал на канале. Давай напишем обработчик излюбленной всеми команды !пиво ).
Получая такую команду наш бот должен проверить, идет ли за ней чей-то ник. Если
да, то он должен сказать что пославший команду налил указаному нику пива. Если
же не идет, то бот обязан сказать что пославший команду налил всем пива.

### парсим полученую строку.
 chop($data);                 ## обрезаем символы конца у строки
 chop($data);                 ## обрезаем символы конца у строки
 @part=split(/:/,$data);
 @tmp=split(/!/,@part[1]);
 $_user=@tmp[0];              # $_user - задавший команду
 @tmp=split(/ /,@tmp[1]);
 $_id=@tmp[0];                # $_id   - идент юзера
 @tmp=split(/ /,@part[1]);
 $_cmd=@tmp[1];               # $_cmd  - IRC команда
 @tmp=split(/ :/,$data);
 $_data=@tmp[1];              # $_data - команда
 
 Эти переменные пригодятся тебе а дальнейшем. Теперь осталось только проверить
$_data на наличие !пиво в начале строки. делается это через регулярные
выражения:

  if($_data=~/^!пиво/){
   ## $_data содержит !пиво в начале строки
  }

 Надо разобрать $_data используя в качестве разделителя пробел, и проверить
наличие 2-го элемента массива. Если он присутствует, то выдаем первый вариант
ответа, если же нет - второй.

 @part=split(/ /,$_data);
 if(@part[1]){
     send (SOCK, "PRIVMSG $chan :$_user налил пива @part[1]\n", 0);
 }else{
     send (SOCK, "PRIVMSG $chan :$_user налил всем по пиву\n", 0);
 }
 
 IRC команда PRIVMSG предназначена для отправки сообщений. Если вместо $chan
указать ник юзера, то сообщение будет отправлено ему в приват.

 Вне всяких сомнений, тебе ни составит ни какого труда написать обработчики
для своих команд. Надеюсь алгоритм ты понял. Что же касается неописаных
сдесь команд IRC, то тебе достаточно просто посидеть и посмотреть какие
данные выдает бот в консоль при появлении той или иной команды на сервере или
канале. Так же советую скачать бота посложнее с нашего сайта. Он тоже написан
на перл, но в нем реализовано довольно много интересных функций. Например
поддержка добавления кода прям на ходу не перегружая бота. Скачать его
можно по этой ссылке.

 Ну вот и все на cегодня. До скорых встреч! =)



© Cobalt 18.05.2006 статья не оптимизирована

e-Commerce Partners Network
Gu3573r написал:

"Эта статья посвящена в первую очередь програмистам которые хотят изучить Perl" - тогда лучше использовать use IO::Socket.
Для пинг-понга легче использовать следюующий код:
if (m/^PING (.*?)$/) { print $socket "PONG $1n"; }
"Выдрать" ник, идент, msg и канал можно легче:
if (m/^(.*?)!(.*?)(s)PRIVMSG(s)(.*?):(.*)/) {
} где $1 = nick, $2 = ident, $5 = channel, $6 = msg.
Посмотрел вашего irc-бота. "операторские команды" можно было сделать намного проще:
if (m/!mode(s)(.*?)(s)(.*)/) { print $socket "MODE $2 $4n"; }
Да и нужно сделать нормальную авторизацию, например командой !login &lt;password&gt;.
P.S. Писал на ночь, если где-то ошибся исправьте. Думаю мои идеи итак ясны.

Ник:

Текст:
P Br B I Qute



Код: обновить
Последние комментарии
22.09.2017 18:36:49 Avito777jaf написал:
<b>Пополение баланса Авито (Avito) за 50%</b> | <b>Телеграмм @a1garant</b> <b>Здравствуйте,...
Новый релиз
22.09.2017 18:26:34 Avito777jaf написал:
<b>Пополение баланса Авито (Avito) за 50%</b> | <b>Телеграмм @a1garant</b> <b>Приветствую...
Сайт снова работает!
22.09.2017 18:12:48 Avito777jaf написал:
<b>Пополение баланса Авито (Avito) за 50%</b> | <b>Телеграмм @a1garant</b> <b>Приветствую...
Новая статья
Реклама

Тут должна была быть ваша реклама, но мы потеряли глиняную табличку с ее текстом. SapeId: 665044

Rambler's Top100