Показать сообщение отдельно

  #7  
Старый 18.06.2007, 09:46
Cobalt
Новичок
Регистрация: 28.03.2007
Сообщений: 7
Провел на форуме:
4007

Репутация: 21
По умолчанию

Раз пошел такой колинкор предлагаю заценить и это кто не видел: http://www.gfs-team.ru/?act=articles&pact=55 - Perl.Irc Bot

Цитата:
В этой статье мы попытаемся охотиться сразу на двух зайцев. А именно, разберем
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
На сайте есть исходник. Плюс немного улучшенная версия перлового бота.
 
Ответить с цитированием