Глава 18 Протоколы Интернета

18.5, Чтение почты на серверах РОРЗ

Проблема

Требуется принять почту с сервера РОРЗ. Например, программа может получать данные о непрочитанной почте, перемещать ее с удаленного сервера в локальный почтовый ящик или переключаться между Интернетом и локальной почтовой системой.

Решение

Воспользуйтесь модулем Net::POP3 с CPAN:
$рор = Net::POP3->new($mail_server)
or die "Can't open connection to $mail_server : $!\n";
$pop->login($username, $password)
or die "Can't authenticate: $!\n";
$messages = $pop->list
or die "Can't get list of undeleted messages: $!\n";
foreach $msgid (keys %$messages) {
$message = $pop->get($msgid);
unless (defined $message) {
warn "Couldn't fetch $msgid from server: $!\n";
next;
}
# $message - ссылка на массив строк
$pop->delete($msgid);
}

Комментарий

Традиционно в доставке почты участвовали три стороны: МТА (транспортный почтовый агент - системная программа типа sendmail) доставляет почту в накопитель (spool), а затем сообщения читаются с помощью MUA (пользовательские почтовые агенты - программы типа Модуль Net::POP3 от CPAN обслуживает клиентскую сторону POP. Иначе говоря, он позволяет программе на Perl выполнять функции MUA. Работа с Net::POP3 начинается с создания нового объекта Net::POP3. Конструктору new передается имя сервера РОРЗ:
$рор = Net: :POP3->new( "pop.myisp.-com" )
or die "Can't connect to pop.myisp.com: $!\n";

При возникновении ошибок все функции Net::POP3 возвращают undef или пустой список в зависимости от контекста вызова. При этом переменная $! может содержать осмысленное описание ошибки (а может и не содержать).
Кроме того, конструктору new можно передать дополнительные аргументы и определить тайм-аут (в секундах) для сетевых операций:
$рор = Net::POP3->new( "pop.myisp.com",
Timeout => 30 ) or die "Can't connect to pop,myisp.corn : $!\n";

Метод login выполняет аутентификацию на сервере РОРЗ. Он получает дв;1 аргумента - имя пользователя и пароль, но оба аргумента являются необязательными. Если пропущено имя пользователя, используется текущее имя. Если пропущен пароль, Net::POP3 пытаетс
$pop->login("gnat", "S33kr1T Pa55wOrD")
or die "Hey, my username and password didn't work!\n";
$pop->login( "midget" ) # Искать пароль с помощью Net::Netrc
or die "Authentication failed.\n";
$pop->login() # Текущее имя пользователя и Net::Netrc
or die "Authentication failed. Miserably.\n";

При вызове метода login пароль пересылается по сети в виде обычного текста. Это нежелательно, поэтому при наличии модуля MD5 от CPAN можно воспользоваться методом арор. Он полностью идентичен login за исключением того, что пароль пересылается в тексто
$рор->арор( $username, $password )
or die "Couldn't authenticate: $!\n";

После аутентификации методы list, get и delete используются для работы с накопителем. Метод list выдает список неудаленных сообщений, хранящихся в накопителе. Он возвращает хэш, где ключом является номер сообщения, а ассоциированное значение - размер
%undeleted = $pop->list();
foreach $msgnum (keys %undeleted) {
print "Message $msgnum is $undeleted{$msgnum} bytes long.\n";
}

Чтобы принять сообщение, вызовите метод get с нужным номером. Метод возвращает ссылку на массив строк сообщения:
print "Retrieving $msgnum : ";
$message = $pop->get($msgnum);
if ($message) {
# succeeded
print "\n";
print @$message; # Вывести сообщение
} else {
# failed
print "failed ($!)\n";
}

Метод delete помечает сообщение как удаленное. При вызове метода quit, завершающего сеанс РОРЗ, помеченные сообщения удаляются из почтового ящика. Метод reset отменяет все вызовы delete, сделанные во время сеанса. Если сеанс завершается из-за того, чт Возможно, вы заметили, что мы ничего не сказали об отправке почты. РОРЗ поддерживает только чтение и удаление существующих сообщений. Новые сообщения приходится отправлять с помощью программ типа mail или sendmail или протокола SMTP. Другими словами, реце Основная задача РОРЗ - подключение почтовых клиентов к почтовым серверам - также выполняется протоколом IMAP. IMAP обладает более широкими возможностями и чаще используется на очень больших узлах.

> Смотри также -------------------------------
Документация по модулю Net::POP3 с CPAN; RCS 1734, "РОРЗ AUTHentication command"; RFC 1957, "Some Observations on Implementations of the Post Office Protocol".

18.6. Программная имитация сеанса telnet

Проблема

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

Решение

Воспользуйтесь модулем Net::Telnet с CPAN:
use Net::Telnet;
$t = Net: :Telnet->new( Timeout => 10,
Prompt => '/%/', Host => $hostname );
$t->logln($username, $password);
@files = $t->cmd("ls"):
$t->print("top");
(undef, $process_string) = $t->waitfor('/\d+ processes/');
$t->close;

Комментарий

Модуль Net::Telnet поддерживает объектно-ориентированный интерфейс к протоколу telnet. Сначала вы устанавливаете соединение методом Net:: Telnet->new, a затем взаимодействуете с удаленным компьютером, вызывая методы полученного объекта. Метод new вызывается с несколькими параметрами, передаваемыми в хэш-по-добной записи (параметр => значение). Мы упомянем лишь некоторые из многих допустимых параметров. Самый важный, Host, определяет компьютер, к которому вы подключаетесь. По умолчанию ис
Еще один важный параметр - Prompt. При регистрации или выполнении команды модуль Net::Telnet по шаблону Prompt определяет, завершилась ли регистрация или выполнение команды. По умолчанию Prompt совпадает со стандартными приглашениями распространенных
/[\$%">] $/

Если на удаленном компьютере используется нестандартное приглашение'. вам придется определить собственный шаблон. Не забудьте включить в него символы /. Параметр Timeout определяет продолжительность (в секундах) тайм-аута при сетевых операциях. По умолчанию тайм-аут равен 10 секундам.
Если в модуле Net::Telnet происходит ошибка или тайм-аут, по умолчанию инициируется исключение. Если не перехватить его, исключение выводит сообщение в STDERR и завершает работу программы. Чтобы изменить это поведение, передайте в параметре Errmode сс
$telnet = Net::Telnet->new( Errmode => sub { main::log(@_) }, ... );

Метод login передает имя пользователя и пароль на другой компьютер. Успешное завершение регистрации определяется по шаблону Prompt; если хост не выдал приглашения, происходит тайм-аут:
$telnet->login($username, $password)
or die "Login failed: @{[ $telnet->errmsg() ]}\n";
Для запуска программы и получения ее вывода применяется метод cmd. Он получает командную строку и возвращает выходные данные программы. В списковом контексте возвращается список, каждый элемент которого соответствует отдельной строке. В скалярном контекст
Пара методов, print и waitfor, позволяет отделить отправку команды от получения ее выходных данных, как это было сделано в решении. Метод waitfor получает либо набор именованных аргументов, либо одну строку с регулярным выражением Perl:
$telnet->waitfor('/--more--/')

Параметр Timeout определяет новый тайм-аут, отменяя значение по умолчанию. Параметр Match содержит оператор совпадения (см. выше), a String - искомую строковую константу:
$telnet->waitfor(Strlng => 'greasy smoke', Timeout => 30)

В скалярном контексте waitfor возвращает true, если шаблон или строка были успешно найдены. В противном случае выполняется действие, определяемое параметром Errmode. В списковом контексте метод возвращает две строки: весь текст до совпадения и совпавш

> Смотри также ------------------------------
Документация по модулю Net::Telnet с CPAN; RFC 854-856 и дополнения в последующих RFC.

18.7. Проверка удаленного компьютера

Проблема

Требуется проверить доступность сетевого компьютера. Сетевые и системные программы часто используют для этой цели программу ping.

Решение

Воспользуйтесь стандартным модулем Net::Ping:
use Net::Ping;
$p = Net::Ping->new()
or die "Can't create new ping object: $!\n";
print "$host is alive" if $p->ping($host);
$p->close;

Комментарий

Проверить работоспособность компьютера сложнее, чем кажется. Компьютер может реагировать на команду ping даже при отсутствии нормальной фунциона.тьно-сти; это не только теоретическая возможность, но, как ни печально, распространенное явление. Лучше рассма
В форме, показанной в решении, модуль Net::Ping пытается подключиться к эхо-порту UDP (порт 7) на удаленном компьютере, отправить датаграмму и получить эхо-ответ. Компьютер считается недоступным, если не удалось установить соединение, если отправленна
Чтобы использовать другой протокол, достаточно передать его имя при вызове new. Допустимыми являются протоколы tcp, udp и icmp (записываются в нижнем регистре). При выборе протокола TCP программа пробует подключиться эхо-порту TCP (порт 7) удаленного
# Использовать ICMP при наличии привилегий и TCP в противном случае
$pong = Net::Ping->new( $> ? "tcp" : "icmp" );
(defined $pong)
or die "Couldn't create Net::Ping object: $!\n":
if ($pong->ping("kingkong.com")) {
print "The giant ape lives!\n";
} else {
print "All hail mighty Camera, friend of children!\n";
}

Ни один из этих способов не является абсолютно надежным. Маршрутизато ры некоторых узлов отфильтровывают протокол ICMP, поэтому Net::Ping сочтп такие компьютеры недоступными даже при возможности подключения по другим протоколам. Многие компьютеры запр

[> Смотри также --------------------------------
Документация по модулю Net::Ping; страницы руководства ping(8), tcp(3), udp(4) и icmp(4) вашей системы (если есть); RFC 792 и 950.

18.8. Применение whois для получения данных от InterNIC

Проблема

Вы хотите узнать, кому принадлежит домен (по аналогии с командой UNIX whois).

Решение

Воспользуйтесь модулем Net::Whois с CPAN:
use Net::Whois;
$domain_obj = Net::Whois::Domain->new($domain_name)
or die "Couldn't get information on $domain_name: $!\n";
# Вызвать методы объекта
$domain_obj # для получения имени, тега, адреса и т. д.

Комментарий

Сервис whois предоставляется службой регистрации доменных имен и предназначается для идентификации владельца имени. Исторически в системах семейства UNIX эти данные получались с помощью программы whois(\), которая возвращала около 15 строк информации, вкл Модуль Net::Whois, как и whois(i), является клиентом службы whois. Он подключается к серверу whois (по умолчанию используется whois.intemic.net, главный сервер доменов ".corn", ".org.", ".net" и ".edu"). Доступ к данным осуществляется с помощью методов, в Чтобы получить информацию о домене, создайте объект Net::Whois::Domain. Например, для получения данных о perl.org объект создается так:
$d = Net::Whois::Domain->new( "perl.org" )
or die "Can't get information on perl.org\n";

Гарантируется только получение имени домена и тега - уникального идентификатора домена в учетных записях NIC:
print "The domain is called ", $d->domain, "\n";
print "Its tag is ", $d->tag, "\n";

Также могут присутствовать следующие данные: название организации, которой принадлежит домен (например, "The Perl Institute"); адрес компании в виде списка строк (например, ("221В Baker Street", "London")) и страна (например, "United Kingdom" или двух
print "Mail for ", $d->name, " should be sent to:\n";
print map { "\t$_\n" } $d->address;
print "\t", $d->country, "\n";

Кроме информации о самом домене также можно получить сведения о контактных лицах домена. Метод contact возвращает ссылку на хэш, в котором тип контакта (например, "Billing" или "Administrative") ассоциируется с массивом строк.
$contact_hash = $d->contacts;
if ($contact_hash) { print "Contacts:\n";
foreach $type (sort keys %$contact_hash) { print " $type:\n";
foreach $line (@{$contact_hash->{$type}}) { print " $line\n";
} } } else {
print "No contact information.\n";
}


[> Смотри также --------------------------------
Документация по модулю Net::Whois с CPAN; man-страница whois(8) вашей системы (если есть); RFC 812 и 954.

18.9. Программа: ехрn и vrfy

Программа ехрп напрямую общается с сервером SMTP и проверяет адрес с помощью команд EXPN и VRFY. Она не идеальна, поскольку ее работа зависит от получения достоверной информации с удаленного сервера командами EXPN и VRFY. Программа использует модуль Net::
Программа узнает, как она была вызвана, с помощью неременной $0 (имя программы). При запуске под именем ехрп используется команда EXPN; при запуске под именем vrfy используется команда VRFY. Установка команды под двумя разными именами осуществляется с
% cat > ехрn
#!/usr/bin/perl -w
"D % In ехрn vrfy

Передайте программе адрес электронной почты, и она сообщит результаты проверки адреса командой EXPN или VRFY. Если у вас установлен модуль Net::DNS, программа проверяет все хосты пересылки почты (mail exchangers), перечисленные в записи DNS данного ад Без Net::DNS результаты выглядят так:
% ехрn gnat@frii.com Expanding gnat at frii.com (gnat@frii.com):
calisto.frii.com Hello coprolith.frii.com [207.46.130.14],
pleased to meet you
При установленном модуле Net::DNS получен следующий результат:
% ехрп gnat@frii.com Expanding gnat at mail.frii.net (gnat@frii.com):
deimos.frii.com Hello coprolith.frii.com [207.46.130.14],
pleased to meet you Nathan Torkington
Expanding gnat at mx1.frii.net (gnat@frii.com):
phobos.frii.com Hello coprolith.frii.com [207.46.130.14],
pleased to meet you
Expanding gnat at mx2.frii.net (gnat@frii.com):
europa.frii.com Hello coprolith.frii.com [207.46.130.14],
pleased to meet you
Expanding gnat at mx3.frii.net (gnat@frii.com):
ns2.winterlan.com Hello coprolith.frii.com [207.46.130.14],
pleased to meet you 550 gnat... User unknown
Исходный текст программы приведен в примере 18.3. Пример 18.3. ехрп
#!/usr/bin/perl -w
# ехрn - расширение адресов через SMTP use strict;
use 10::Socket;
use Sys::Hostname;
my $fetch_mx = 0;
# Попытаться загрузить модуль, но не огорчаться в случае неудачи
eval {
require Net::DNS;
Net::DNS->import('mx');
$fetch mx = 1;
};
my $selfname = hostname();
die "usage: $0 address\@host ,,,\n" unless @ARGV;
# Определить имя программы - "vrfy" или "ехрп".
my $VERB = ($0 =~ /ve?ri?fy$/i) ? 'VRFY' : 'EXPN' my $multi = @ARGV > 1;
my $ remote;
# Перебрать адреса, указанные в командной строке
foreach my $combo (@ARGV) {
my ($name, $host) = split(/\@/, $combo);
my @hosts;
$host ||= 'localhost';
@hosts = map { $_->exchange } mx($host)
if $fetch_mx;
@hosts = ($host) unless @hosts;
foreach my $host (@hosts) {
print $VERB eq 'VRFY' ? "Verify" : "Expand", "ing $name at $host ($combo):";
$remote = 10::Socket::INET->new( Proto => "tcp", PeerAddr => $host, PeerPort =>
"smtp(25)",
};
unless ($remote) {
warn "cannot connect to $host\n";
next;
}
print "\n";
$ remote->autoflush(1);
# Использовать сетевые разделители строк CRLF
print $remote "HELO $selfname\015\012";
print $remote "$VERB $name\015\012":
print $remote "quit\015\012";
while (<$remote>) {
/~220\b/ && next;
/"221\b/ && last;
s/250\b[\-\s]+//;
print;
}
close($remote) or die "can't close socket: $!
print "\n";

© copyright 2000 Soft group

Используются технологии uCoz