В продолжение темы про сокеты, я решил расписать их особенности на конкретных простых примерах. Почему простых? Чтобы ты смог подвести под мою основу свой собственный скрипт 🙂 Мои примеры будут как бы подсказкой, дополнительной опорой для изучения тобой Perl.
Итак начнем. Самое интересное в сокетах, на мой взгляд - отправка и получение данных. Как я уже сказал, можно обойтись самым простым решением: print и <>. Но для особых случаев, когда в сокете должны быть данные без символа перевода строки (\n), либо пересылка данных в сокет без него, этими операторами не обойтись. Можно использовать, либо объектовые методы $self->recv и $self->send твоего сокета, либо заюзать системные функции языка aka sysread() и syswrite(), но обо всем
по порядку.
Для ожидания данных используют модуль Select.pm, который смотрит, доступен ли сокет для чтения и для записи, и если доступен - с ним производятся нужные операции.
Структура IRC-бота
Я взял самый наболевший и популярный пример, который выполнил в считанные строки кода :). Конечно, умело написанный парсер возвратных данных и управление немного его приукрасит, но, как я уже сказал, это твоя задача 🙂 Собственно скрипт:
#!/usr/bin/perl
use IO::Socket;
use IO::Select;
$sock=IO::Socket::INET->new("irc.server.ru:6667") || die "can\'t create sock\n";
$sock->autoflush(1);
$select=new IO::Select($sock);
syswrite($sock,"USER test test test test\nNick Testor\n");
syswrite($sock,"JOIN #xakep\n");
while(1) {
foreach $s ($select->can_read) {
if ($s eq $sock) {
$sock->recv($msg,1024);
print "Server send to me: $msg\n";
}
}
}
Поясню, как все это работает. В начале, заюзываем 2 модуля Select.pm и Socket.pm. Затем создаем сокет с IRC-сервером (на этом останавливаться не буду, создание сокетов было описано в
первой части статьи) и отключаем в нем буферизацию. Затем идет создание идентификатора $select и занесение в него нашего созданного сокета. После этого, можно будет смотреть за данными в сокете.
Затем пишем в сокет syswrite()'ом идентификационные строки (как IRC-man ты их, конечно, знаешь).
Затем порождаем бесконечный цикл, в котором следим за тем, можно ли, прочитать из сокета данные ($select->can_read возвращает ссылку на массив, в котором хранятся идентификаторы сокетов, где есть инфа для чтения). Сравниваем: если элемент массива соответствует нашему сокету, то читаем из него сообщение и выводим на консоль. Получается быстро и красиво :). Но без парсера этих самых сообщений, твой бот слетает по таймауту с сервера, поэтому не слишком обижайся на него 😉 Просто анализируй каждую строку и направляй ее куда следует. Вот пожалуй и все об этом несложном ламаботе :).
Мучаем WWW-сервер
Уж не знаю для чего тебе может пригодится следующий скрипт 🙂 Может ты его захочешь заюзать для DDoSа какого-нибудь сервака, или в мирных целях - например для раскрутки твоего любимого сайта. Скрипт выполняет следующую роль: плодит нужное количество потомков и просит страницу с Web-сервера 🙂 Все просто как мир. Собственно, код:
#!/usr/bin/perl
use IO::Socket;
$host='rambler.ru';
$port=80;
$dir='/index.html'; ## Сервер, порт и собственно файл, который хотим получить.
$threads = $ARGV[0] || 10; ## Количество потомков задаем в параметре скрипта, или 10 по дефолту
$debug=1; ## Мусорить на экран или нет решать тебе, по умолчанию, нет
init(); ## Идем на главную процедуру.
sub init { ## Собственно, главная процедура 🙂
for (1..$threads) { ## Создаем цикл от единицы до заданного числа
unless($pid=fork()) { ## Ответвляем процесс
print "starting!\n" if ($debug); ## Флудим в консоль, если $debug=1
fconnect(); ## Коннектимся каждым потомком к серверу.
}
}
}
sub fconnect {
my($sock);
$sock=IO::Socket::INET->new("$host:$port") || return 1; ## Создаем сокет
print $sock qq~GET $dir HTTP/1.0
Host: $host
~; ## Запрашиваем у Web-сервера нужный документ
$count=sysread($sock,$msg,1024); ## Читаем ответ
print "sock is alive\n" if ($count > 0 && $debug); ## Если ответ был успешно доставлен и дебаг включен - опять флудим 🙂
close($sock); ## Закрываем сокет
exit; ## И завершаем потомок! Этот выход очень важен (иначе будет переполнение в таблице процессов)
}
И тут, опять же все просто, многопотоковость очень гибко взаимодействует с сокетами, и выполняет нужную функцию. Сам посуди, откроется одновременно нужное количество потомков и будут обращаться к сокету, что гораздо быстрее последовательных операций, особенно если канал это позволяет :).
Это далеко не все прелести Perl, которые можно выполнять с сокетами. В Perl можно писать демоны, просто сервера с многопотоковым подключением, двусторонние сервера, и многое другое. Об этом можно написать отдельную книгу, поэтому заморачивать тебя особыми сложностями я не буду. Практика показывает, что даже с такими элементарными операциями можно писать довольно серьезные проекты.
Удачи в кодинге!