http://www.nadomnik.by.ru/


Hello, Perl! Perl FAQ по-русски. Часть 7

Дмитрий Репин aka cmapuk[0nline]

Продолжаем практиковаться в программировании на языке Perl. В этой части мы рассмотрим вопросы сетевого программирования, а также узнаем о некоторых полезных модулях.

Сетевые приложения с Net::XXX. Модули класса Net предоставляют возможность работать с различными протоколами прикладного уровня. Это и FTP, и почтовые POP3 и IMAP, и многие другие. Есть также такие возможности, как работа с через proxy. Краткий рассказ о работе с этими модулями и другую документацию можно взять на сайте http://www.pobox.com/ ~gbarr/libnet/. Вот небольшой обзор семейства Net:

Net::FTP - Работа с FTP
Net::IMAP::Simple - Проверить почту с IMAP-сервера
Net::IRC - Написать клиента для IRC
Net::NNTP - Работа с News протоколом
Net::Ping - Ping, как он есть )
Net::POP3 - Почта POP3
Net::Printer - Печать на принтер
Net::SMTP Отправка писем через SMTP
Net::SMTP::Server - Создание SMTP-сервера
Net::SOCKS - Работа с SOCKS-сервером
Net::SSH - Работа с секьюрным шеллом
Net::Telnet - Телнет
Net::Whois - Поиск доменов через InterNIC
Net::ICQ2000 - Написать свою аську на Perl ;-))

Все семейство этих модулей называется libnet (также как семейство модулей LWP называется libwww-perl), и вы можете использовать это название при поиске информации в поисковых системах. Большинство модулей работают одинаково как под *nix-системы, так и под всеми любимой и ненавидимой Windows.

Проверим почту с сервера www.pisem.net

use Net::IMAP::Simple;
$user="username@pisem.net";
$pass="Мою кошку зовут JHf^!hdg+/"
$server = new Net::IMAP::Simple-('smtp.hotbox.ru'); # Подключаемся
$server->login($user,$pass); # Логинимся
$mess_num = $server->select('INBOX'); # Выбираем папку INBOX
foreach $msg ( 1..$mess_num ) {
         $lines = $server->get($msg);         # Получаем письмо в виде ссылки на массив строк
         print @{$lines};         # Распечатываем на экран
}
$server->quit();                 # Отключаемся

Примерно таким же образом происходит работа с другими модулями семейства Net

Возможно, вам может понадобиться работать с сетевыми пакетами на низком уровне, например собирать/разбирать UDP-пакеты. Здесь вам понадобятся модули семейства NetPacket. Для каждого протокола нужно подключать модуль NetPacket::ИмяПрото-кола. Например NetPacket::UDP, NetPacket: :Ethernet, NetPacket::TCP и и.п.

# Простейший POP3-сниффер из документации NetPacket::TCP
use Net::PcapUtils; # Модуль для отлова пакетов
use NetPacket::Ethernet qw(:strip);
use NetPacket::IP qw(:strip);
use NetPacket::TCP;
sub process_pkt {
         my($arg, $hdr, $pkt) = @_;
         my $tcp_obj = NetPacket::TCP->decode(ip_strip(eth_strip($pkt)));
         if (($tcp_obj->{src_port} == 110) or ($tcp_obj->{dest_port} == 110)) {
print($tcp_obj->{data});
}
}
# Прослушиваем канал на предмет TCP-пакетов.
# Для "пойманного" пакета выполняется proccess_pkt
Net::PcapUtils::loop(\&process_pkt, FILTER => 'tcp');

Как произвести сжатие данных? Вам поможет модуль Compress::Zlib. Он позволяет не только работать с файлами, но и архивировать/разархивировать данные "на лету".

use Compress::Zlib;
$compressed = compress($source);
$source = uncompress($compressed);

Подробнее обо всех возможностях модуля - в perldoc Compress::Zlib.

Шифрование данных. Вы наверняка интересовались, как шифровать и расшифровывать данные с помощью Perl. Здесь пригодится модуль Crypt::DES или его собратья (Crypt::Blowfish и т.п.).

use Crypt::DES;
$key = pack("H16", "0123456789ABCDEF");
$crypt = new Crypt::DES $key;
$crypted = $cipher->encrypt($mytext);
$mytext = $crypt->decrypt($crypted);

Работа с файлами. Если вы не хотите изобретать механизмы различных манипуляций с файлами, то воспользуйтесь модулями семейства File

File::Compare - Сравнение файлов
File::Find - Поиск файлов
File::Path - Создание/Удаление дерева директорий
File::Spec - Манипуляции именами файлов/директорий
File::stat - Интерфейс к стандартной функции stat()
File::Temp - Работа с временными файлами/директориями
use File::Path;
mkpath($array_of_dirnames_reference, 0, 0755);
rmtree($array_of_dirnames_reference, 1);

Здесь первый парамер - ссылка на массив путей новых директорий. Второй - флажок true/false - сообщать о каждой операции или все делать "молча". Третий параметр у mkpath - права.

Форматы текста. Переводы текста между различными форматами (TXT, POD, RTF, HTML, etc) - дело непростое, и лучше всего доверить его соответствующим модулям. Рассмотрим для начала семейство HTML.

Объекты некоторых из модулей этого семейства интегрируются с LWP-обьектами. Чуть ниже вы это увидите.

HTML::AsSubs - Построение страницы HTML-функциями
HTML::Entities - Кодирование символов типа c <=> ©
HTML::Filter - Фильтр для удаления тегов
HTML::Form - Создание форм
HTML::HeadParser - Разбор блока HEAD
HTML::LinkExtor - Выборка линков из страницы
HTML::Parser - Парсер HTML
HTML::Tree - Создание дерева вложенно-сти тегов
# Выборка формы из страницы и ее последующая отправка
use HTML::Form;
$form = HTML::Form->parse($html_page, $base_uri);
$form->value(query => "Perl");
use LWP;
LWP::UserAgent->new->request($form->click);
...

POD-формат - формат для документации. В комплекте Perl есть утилиты pod2text, pod2html и т.п. для преобразования в более читабельный вид ;-). Кроме того, имеется семейство модулей POD::***, позволяющее работать с этим форматом и преобразовывать его в нормальное для чтения представление.

Для работы с RTF-текстами имеются модули RTF::Document, RTF::HTML::Converter, и т.п.. Правда, эти модули очень плохо относятся к русским буквам и другим чуждым "буржуинским" программерам символам. Но это не беда. Откройте файл модуля RFT::HTML::Converter (и RFT::Text::Converter тоже) и в строке номер 77 сделайте следующую поправку:

"&#$_;" на сhr($_). Иначе все символы, не являющиеся английскими буквами, превратятся в &#[КодASCII].

Очень силен в обращении с текстовыми данными модуль Text (точнее, его семейство). Это даже не модуль, а целый текстовый процессор, не хуже Word.

use Text::Autoformat;
$formatted = autoformat $rawtext, { left=>8, right=>70,
justify => 'centre',
case => 'lower'
};

И это самое малое, что можно сделать с текстом с помощью Text::***. Конвертирование форматов разных ОС, фильтрация, макросы, текстовая графика и многое другое. Что называется, "MustHave".

С кодировками Unicode и всеми проблемами, с ней связанными, вам помогут справиться модули Unicode::***

Модуль Unicode::String позволяет работать со строками этой кодировки, не перекодируя их вручную.

use Unicode::String qw(utf8 utf16 hex);
$u = utf8("Unicode uniform string");
$u16 = $u->utf16; # Перевод в utf16
$hex = $u->hex; # в Hex-строку
$ucopy = $u->copy;
$u->chop;
$u->length;
$u->index($u2);
$u->substr($offset, $length);

Работать с форматом PDF (создавать, читать, писать) вам поможет модуль PDF со всеми своими подмодулями, а также семейство Text::PDF. Они предоставляют вам мощный интерфейс для всевозможных манипуляций с PDF-данными. Вы можете, например, написать скрипт, который будет выдавать красивый вариант страниц вашего сайта для печати. Правда, посетителям с подключением Dial-Up это будет не очень удобно =).

use PDF::Create;
$pdf = new PDF::Create('filename' => 'HelloPerl.pdf',
'Version' => 1.2,
'PageMode' => 'UseOutlines',
'Author' => 'cmapul[0nline]',
'Title' => 'Hello, Perl!',
  );
$root = $pdf->new_page('MediaBox' => [ 0, 0, 612, 792 ]);
$page = $root->new_page;
$f1 = $pdf->font('Subtype' => 'Type1',
'Encoding' => 'WinAnsiEncoding',
'BaseFont' => 'Helvetica');
$page->stringc($f1, 20, 300, 300,'by cmapuk[0nline] ');
$pdf->close;

LWP Cooking. Снова я возвращаюсь к вопросам работы с LWP, как и обещал, чтобы рассказать о модулях этого семейства подробнее. Несколько позже мы рассмотрим и модули более низкого уровня - Socket и IO::Socket. Самый простой способ использования LWP:

cmd> perl -MLWP::Simple -e "getprint 'http://www.comprice.ru';" >index.html

Если ваша консоль поддерживает перенаправление (символы <>), то индексная страница сайта будет записана в index.html.

Теперь напишем что-нибудь посложнее. Создадим скрипт для скачивания архивов Perl-модулей с сайта ActiveState (www.activestate.com/ PPMPackages/zips/6xx-builds-only/). Для начала определимся, какими возможностями должна обладать программа.

1) Скачивание списка модулей.

2) Вывод списка в файл.

2) Скачивание модулей выборочно по списку

3) Возможность соединения через прокси-сервер.

4) Сохранение архивов в заданной директории.

Теперь можно создать конфигурационный файл.

# pmdown.cfg
# Адрес страницы списка модулей
baseurl=http://www.activestate.com/ PPMPackages/zips/6xx-builds-only
# Если прокси не используется, оставить эти поля пустыми
proxy_addr=192.168.0.1
proxy_port=3128
# Если не используется авторизация на прокси-сервере, эти поля оставить пустыми
proxy_user=cmapuk
proxy_pass=superpassword
# Директория для сохранения
savedir=/home/users/cmapuk/modules

Наша программа будет принимать 2 параметра в командной строке:

Ключ, определяющий действие, и имя файла, в следующих комбинациях:

cmd> pmdown -l list.txt скачать список модулей и записать в файл list.txt;
cmd> pmdown -d list2.txt открыть файл list2.txt и скачать все модули из списка.

При запуске без параметров будем выдавать help.

#!/path/to/perl
if(@ARGV<2){ # Если аргументов меньше двух - пишем хелп и завершаемся
print < [Usage]: pmdown

Пример кода не блещет красотой исполнения, но зато так выглядит нагляднее. В качестве "домашнего задания" могу предложить оптимизировать код примера или расширить его возможности. Если ваш новый скрипт будет работать, значит, я не зря потратил время, взявшись за написание этой статьи ;-).

Источник: "Компьютер Price", http://www.comprice.ru

 


Copyright © "Internet Zone", http://www.izcity.com/, info@izcity.com