Книга: Язык программирования Perl

Лекция 17. Работа в IP-сетях

Лекция 17. Работа в IP-сетях

В этой лекции рассказывается об имеющихся в Perl возможностях обработки данных в IP-сетях, начиная с низкоуровневых средств и заканчивая классами для работы с основными сетевыми протоколами.

Цель лекции: узнать основные механизмы передачи данных по сети и научиться применять их для обработки данных в своих программах, используя стандартные и дополнительные модули Perl.

Сегодня большинство пользователей компьютеров воспринимают возможность обмена данными по компьютерной сети как нечто само собой разумеющееся. Это может быть небольшая офисная сеть из нескольких станций, корпоративная сеть, объединяющая многие сотни компьютеров, или подключение к глобальной сети Интернет. Легкость и удобство работы с многочисленными сетевыми сервисами стала возможной благодаря длительным усилиям многих выдающихся программистов, самых разных компаний и организаций из многих стран мира по созданию существующей инфраструктуры сетевых технологий. Эта инфраструктура основана на огромном числе стандартов, позволяющих согласованно использовать линии связи, аппаратуру передачи данных, компьютеры, операционные системы и прикладные программы для обмена информацией по сети.

Подавляющее большинство широко используемых сетей работает на основе протокола передачи данных IP (Internet Protocol), обеспечивающего надежное перемещение информации между компьютерами в разных сетях. Протокол - это система правил для согласованного взаимодействия при обмене информацией. При сетевом взаимодействии используется целый набор протоколов, обычно называемый стеком протоколов, который подразделяется на несколько уровней. На каждом из уровней выполняются определенные действия и преобразования данных. Протокол IP отвечает за сетевой уровень доставки информации, разделенной на специальные блоки данных, которые называются пакетами (packet).

Для идентификации объединенных в сети компьютеров или других сетевых устройств, обобщенно называемых хостами (host), используются последовательности из четырех чисел - IP-адреса: например, 192.168.82.83 или 172.16.2.73. Назначенный IP-адрес служит уникальным идентификатором хоста в конкретной сети. Кроме того, каждый хост, настроенный на работу с протоколом IP и даже не подключенный к сети, имеет собственный специальный адрес 127.0.0.1 - что-то вроде местоимения "я" на языке сетевых коммуникаций. Хост может иметь доменное имя, соответствующее его IP-адресу, например, имя хоста www.perl.com соответствует адресу 208.201.239.36. Собственному адресу 127.0.0.1 соответствует специальное имя localhost. Поскольку на каждом хосте может выполняться несколько сетевых программ, то для распределения между ними получаемых и отправляемых пакетов используются дополнительные числовые обозначения, так называемые номера портов. Поэтому программная точка отправления или доставки данных в IP-сетях определяется сочетанием адреса и порта, разделенных двоеточием. Многие номера портов по общепринятым соглашениям закреплены за определенными сетевыми службами. Например, обращение к web-серверу на текущей машине будет происходить по адресу и порту 127.0.0.1:80, а к почтовому серверу - по 127.0.0.1:25.

Для установления соединения между хостами и обмена данными в IP-сетях применяется механизм сокетов. Сокеты (socket) можно рассматривать как логические каналы двусторонней связи между сетевыми программами. Сокет определяется адресом хоста, номером порта и используемым протоколом обмена данными. Для организации пересылки данных между программами применяется один из двух протоколов транспортного уровня - UDP или TCP, выполняющихся поверх протокола IP. Протокол UDP (User Datagram Protocol) применяется для обмена независимыми блоками данных, называемыми дейтаграммами (datagram), без их гарантированной доставки адресату. Например, с использованием протокола UDP отправляются запросы управления устройствами или пересылается аудио- или видеотрансляция, когда потеря нескольких передаваемых пакетов не слишком существенна. Протокол TCP (Transmission Control Protocol) применяется для передачи по сети потока данных. При этом контролируется гарантированная доставка упорядоченной последовательности пакетов адресату. При помощи протокола TCP, например, отправляется электронная почта, передаются файлы и доставляются web-страницы.

Даже если в большинстве случаев при сетевом программировании на Perl используются более высокоуровневые средства, полезно хотя бы очень бегло познакомиться с принципами обмена данными через сокеты. Особенностью Perl, отражающей его сетевую направленность, стало то, что многие примитивные сетевые операции встроены в ядро языка, например: socket, socketpair, getsockname, getpeername, setsockopt, bind, listen, accept, send, recv, shutdown. Но гораздо удобнее и надежнее пользоваться стандартными модулями, реализующими средства работы с сокетами. В стандартном модуле Socket определены вспомогательные функции для работы с сокетами. Например, функция inet_ntoa() преобразует в строку двоичное представление IP-адреса, которое возвращает встроенная функция gethostbyname. А функция inet_aton() преобразует строковое представление адреса в двоичный вид, требуемый для встроенной функции gethostbyaddr, определяющей доменное имя хоста по IP-адресу. Работу этих функций можно показать на таком примере:

use Socket; # используем модуль работы с сокетами
my $host_name = 'www.perl.com'; # по имени хоста
my $address = gethostbyname($host_name); # узнаем адрес и
my $ip_address = inet_ntoa($address); # преобразуем его
print "$ip_address $host_namen"; # в строку
# результат: 208.201.239.36 www.perl.com
$address = inet_aton($ip_address); # и обратно
my $host_name = gethostbyaddr($address,AF_INET);# узнаем имя
print "$ip_address $host_namen"; # по адресу
# результат: 208.201.239.36 www.perl.com

Класс IO::Socket предоставляет объектный интерфейс для встроенных функций и помогает справиться со многими трудностями и избежать некоторых ошибок при программировании передачи данных через сокеты. Максимально упрощенный пример демонстрирует написание сервера для приема сообщений по протоколу TCP:

use IO::Socket; # используем класс работы с сокетами
my $server_port = 5555; # порт для обмена
my $server = IO::Socket::INET->new( # создаем сокет
LocalPort => $server_port, # на порту
Type => SOCK_STREAM, # для потокового обмена
Proto => 'tcp', # по протоколу TCP
Listen => 10, # с 10-ю соединениями
Reuse => 1) #
or die "Ошибка запуска TCP сервера на $server_port ($@)";
while (my $client = $server->accept()) { # создаем поток для
$client->autoflush(1); # клиента, очищаем буфер,
my $message = <$client>; # читаем сообщение из него
print $client "OKn"; # посылаем ответ клиенту
close $client; # и закрываем поток
print STDERR $message; # выводим сообщение
last if $message =~ /STOP/i; # выходим из цикла, если
} # в сообщении есть STOP,
close $server; # и закрываем сокет

Сокеты могут использоваться не только для обмена данными по сети, но и для межпроцессного взаимодействия, когда сервер и клиент работают на одном и том же компьютере. Для доступа к приведенному серверу можно использовать, например, такую клиентскую программу:

use IO::Socket; # используем модуль работы с сокетами
my $server_host = '127.0.0.1'; # адрес сервера
my $server_port = 5555; # и порт на нем
my $socket = IO::Socket::INET->new( # создаем сокет
Type => SOCK_STREAM, # для потокового обмена
Proto => 'tcp', # по протоколу TCP
PeerAddr => $server_host, # с удаленным адресом
PeerPort => $server_port) # и портом
or die "Ошибка соединения с $remote_host:$remote_port ($@)";
# сообщение задается
my $message = $ARGV[0] || # параметром программы
"Проверка связи!"; # или умолчанием
print $socket "$messagen"; # отправляем его и
my $answer = <$socket>; # принимаем ответ
print "$answer"; # выводим ответ
close $socket; # и закрываем сокет

Из этого незатейливого примера можно сделать такой вывод: для согласованной работы клиент и сервер должны следовать установленным "правилам общения" во время сеанса обмена данными, так называемому протоколу прикладного уровня. В нашем случае правила сводятся к тому, что обмен идет по порту 5555, сервер ждет от клиента только одно сообщение, клиент ждет обязательного ответа от сервера, который завершает работу по получении сообщения, в котором содержится строка 'STOP'. Подробные соглашения описываются в конкретных протоколах сетевого обмена, например: HTTP (передача гипертекстовых документов), SMTP (отправка электронной почты), FTP (передача файлов). Описание подобных протоколов и других соглашений публикуются в виде предложений RFC (Request For Comment) - фактических международных стандартов, на которые ориентируются разработчики сетевого программного обеспечения.

Во Всемирной сети Интернет насчитывается огромное количество файловых серверов, где хранятся архивы программ, документация и другая информация. FTP (File Transfer Protocol) - это протокол, специально созданный для передачи файлов. Обмен файлами остается одной из постоянных задач сетевого программирования, которая легко решается средствами языка Perl. В поставке Perl имеется стандартный модуль Net::FTP, реализующий FTP-клиента, который позволяет весьма просто организовать обмен файлами с сервером по протоколу FTP - например, автоматизировать автоматическое обновление нужных файлов с сервера. Далее приводится программа, которая с помощью команд FTP загружает с сервера файл, если он имеет более позднее время изменения, чем его локальная копия:

use Net::FTP; # используем модуль работы с FTP
my $server = 'ftp.server.org'; # имя или адрес сервера
my $file = 'file.name'; # имя файла
my $ftp = Net::FTP->new($server) # соединяемся с сервером
or die "Ошибка соединения с $server:$@";
$ftp->login('ftp','ftp') # указываем имя и пароль
or die " Ошибка регистрации:", $ftp->message;
$ftp->cwd("/pub") # переходим в каталог
or die "Ошибка смены каталога:", $ftp->message;
my $time_ftp = $ftp->mdtm($file) # время изменения на сервере
or die;
my $time_old = (stat($file))[9]; # время создания копии
if ($time_ftp > $time_old) { # если файл на сервере новее,
$ftp->binary; # то в двоичном режиме
$ftp->get($file) # загружаем файл
or die "Ошибка загрузки: ", $ftp->message;
utime($time_ftp, $time_ftp, $file); # и меняем время файла
}
$ftp->quit; # заканчиваем сеанс связи

Поскольку в классе Net::FTP реализованы остальные команды протокола FTP, с его помощью можно разрабатывать гораздо более сложные программы файлового обмена. Кроме этого класса, в архивах CPAN можно найти много других модулей для обмена файлами с FTP-серверами.

Электронная почта (e-mail) была и остается одним из самых популярных сетевых сервисов. Электронная почта базируется на асинхронной доставке почтового сообщения (message) с одного почтового сервера на другой с помощью протокола SMTP (Simple Mail Transfer Protocol). Почтовые сообщения каждого пользователя хранятся на сервере в отдельном почтовом ящике (mail-box). Клиентская почтовая программа (Mail User Agent, MUA) забирает почту с сервера с помощью одной из версий протокола POP (Post-Office Protocol) или предоставляет пользователю непосредственный доступ к ящику на почтовом сервере с помощью протокола IMAP (Internet Mail Access Protocol).

Естественно, что в Perl имеется множество средств работы с электронной почтой. По электронной почте можно организовать автоматическое уведомление системных администраторов или пользователей о наступлении определенного события. С помощью сообщений электронной почты организуется регулярная автоматическая рассылка информации, например, счетов клиентам. При работе с почтой можно воспользоваться стандартными модулями - Net::SMTP для отправки сообщений и Net::POP3 для их получения. Приведем пример простой программы, отправляющей сообщение электронной почты:

use Net::SMTP; # используем класс для отправки e-mail
my $mail_server = 'shokhirev.com'; # почтовый сервер
my $to_user = '[email protected]'; # получатель
my $from_user = '[email protected]'; # отправитель
$smtp = Net::SMTP->new(Host=>$mail_server);# соединяюсь
$smtp->mail($from_user); # пишу
$smtp->to($to_user); # получателю
$smtp->data(); # письмо
$smtp->datasend("To: $to_usern"); #
$smtp->datasend("Subject: Lectures on Perl 5n");
$smtp->datasend("n");
$smtp->datasend("Сообщаем о публикации на intuit.run");
$smtp->datasend("курса лекций по Perl 5n");
$smtp->dataend(); # заканчиваю
$smtp->quit; # отсоединяюсь

Если нужно в программе проверить почтовый ящик на сервере, то с помощью класса Net::POP3 не составит труда написать короткую программу, принимающую электронную почту. Например, такую:

use Net::POP3; # используем класс для получения e-mail
my $mail_server = 'shadrinsk.net'; # почтовый сервер
my $user = 'mshock'; # почтовый ящик
my $password = 'secret'; # пароль
$pop = Net::POP3->new($mail_server); # подключаюсь
if ($pop->login($user, $password) > 0) {# регистрируюсь
my $numbers = $pop->list; # получаю номера писем
foreach my $numbers (keys %$numbers) {# по номеру
my $message = $pop->get($numbers); # получаю письмо
print @$message; # печатаю его
$pop->delete($numbers); # удаляю с сервера
}
}
$pop->quit; # отсоединяюсь

На серверах CPAN есть множество программ для работы с электронной почтой, включая серверы. На Perl написана свободно распространяемая почтовая система с web-интерфейсом Open WebMail (openwebmail.org). На нем же написана и одна из самых известных и эффективных серверных систем фильтрации спама - SpamAssassin.

Системы мгновенного обмена сообщениями (instant messaging), иногда также называемые Интернет-пейджерами, получили огромное распространение: миллионы людей ежедневно общаются с помощью ICQ, Jabber, AOL Instant Messenger или Yahoo!Messenger. В архивах на сайте CPAN можно найти Perl-модули для работы со всеми этими системами. Хотя этот обмен сообщениями ориентирован на взаимодействие людей, его можно использовать для программного извещения пользователя о каком-либо событии. Для примера напишем программу, отправляющую сообщение с использованием открытого протокола мгновенного обмена сообщениями XMPP/Jabber (дополнительный модуль Net::Jabber нужно установить из архива CPAN). В примере после соединения с Jabber-сервером отправляется сообщение пользователю, а после получения от него ответа работа завершается:

use Net::Jabber; # подключаем класс работы с Jabber
use utf8; # в Jabber используется UTF-8
my $server = 'jabber.shadrinsk-city.ru'; # сервер
my $port = 5222; # порт
my $username = 'perl'; # отправитель
my $password = 'password'; # его пароль
my $resource = 'jud'; # ресурс
my $to_user = '[email protected]'; # получатель
my $client = new Net::Jabber::Client(); # создаем клиента
$client->SetCallBacks( # указываем обработчики событий:
onconnect => &on_connect, # при подключении
onauth => &on_auth, # при регистрации
message => &on_message, # при получении сообщения
$client->Execute( # соединяемся с сервером
hostname=>$server, port=>$port,
username=>$username, password=>$password,
resource=>$resource, register=>1,
connectsleep=>0, connectattempts=>1,
# завершение программы произойдет в on_message
sub on_connect { # выполнится при подключении к серверу
print "Подключен к $server:$portn";
}
sub on_auth { # выполнится при регистрации на сервере
print "Зарегистрирован как $usernamen";
$client->MessageSend( # ОТПРАВЛЯЕМ СООБЩЕНИЕ
to=> $to_user. '/' .$resource,
subject=>'сообщение от Perl',
body=>'Привет, Jabber!'
}
sub on_message { # выполнится при получении сообщения
my $sid = shift; # извлекаем номер и текст
my $message = shift; # ответа и выводим его:
print "Тема:", $message->GetSubject(), "n";
print "Сообщение:", $message->GetBody(), "n";
$client->Disconnect(); # отключаемся от сервера
exit(0); # и завершаем работу
}

В этом примере демонстрируется прием программирования, распространенный при работе в многозадачной среде: главная программа организует бесконечный цикл обработки событий, для реагирования на которые вызываются обработчики событий. Конечно, помимо обмена сообщениями Jabber предоставляет целый набор средств для полноценного общения, а Perl дает возможность работать с ними.

Есть примеры использования Perl для разработки шлюзов между IP-сетями и беспроводными сетями. На Perl написан свободно распространяемый пейджинговый шлюз Sendpage (www.sendpage.org). Класс Net::SNPP занимается отправкой сообщений на пейджер по протоколу SNPP (Simple Network Paging Protocol), а модуль Net::SMS служит для работы со службой SMS-сообщений для клиентов GSM-телефонии. Теперь мало кого удивляет, что вскоре после появления очередной новой технологии передачи данных на CPAN выкладываются Perl-модули для работы с ней.

Крупную компьютерную сеть можно сравнить с живым организмом: сетевое оборудование и компьютеры - это ее органы, а линии связи - нервные волокна. Сеть ежеминутно меняет свое состояние, ее составные части могут "болеть" и "отмирать", сеть может "задыхаться" от чрезмерного объема передаваемых данных (сетевого трафика). Для мониторинга состояния сети, ее обслуживания и диагностики неисправностей применяются различные служебные программы. Некоторые из них написаны на языке Perl. В других случаях Perl применяется для "склеивания" разных программ в единую систему управления сетью. Если вспомнить, что Perl был создан системным администратором, то станет понятным, почему имеется так много модулей, так или иначе связанных с управлением сетями. В качестве простейшего примера можно привести стандартный класс Net::Ping, с помощью которого можно проверить работоспособность хоста по его IP-адресу. В ОС MS Windows это делается такой командой:

perl -MNet::Ping -e"print Net::Ping->new()->ping('10.0.0.1')"

В ней запускается компилятор perl, который подключает модуль (-M) Net::Ping и выполняет выражение (-e), заключенное в двойные кавычки. А в выражении выводится результат обращения к методу ping класса Net::Ping с IP-адресом в качестве аргумента. В результате выполнения будет выведен адрес хоста и две 1, если хост активен, или два 0, если он не ответил.

Многие программные средства управления компьютерными сетями основаны на протоколе SNMP (Simple Network Management Protocol), использующего для обмена данными протокол UDP. Такие программные средства построены по принципу периодического опроса так называемых агентов, которые отвечают на запросы управляющей программы и передают ей информацию, накопленную во время работы подключенного к сети устройства - компьютера, принтера, маршрутизатора и так далее. Категории собираемой информации (управляемые устройства и их характеристики) имеют унифицированные имена и числовые идентификаторы объектов (Object IDentifier, OID), которые присваиваются производителями устройств в соответствии со стандартами описания "базы данных управляющей информации" MIB (Management Information Base). При определенных условиях по протоколу SNMP можно не только считывать по сети информацию с устройств, но и управлять этими устройствами, изменяя их характеристики. С помощью протокола SNMP можно также организовать управление программными комплексами, например, операционными системами и СУБД. На Perl написаны модули для работы c SNMP-агентами. Для иллюстрации сказанного приведем простой пример, в котором опрашивается агент, работающий на персональном компьютере, и у него запрашиваются две характеристики - описание системы и время ее работы:

use Net::SNMP; # используем класс для работы с SNMP
my ($session, $error) = Net::SNMP->session( # сеанс работы
-hostname => '192.168.82.83', # с хостом,
-community => 'public', # группой
-port => 161 # и портом
defined($session) or die ("Ошибка сеанса SNMP: $error");
# запрашиваем информацию о компьютере по
# коду (OID) и идентификатору объекта MIB:
info('1.3.6.1.2.1.1.1.0', 'sysDescr'); # описание системы
info('1.3.6.1.2.1.1.3.0', 'sysUpTime'); # время работы
$session->close(); # завершаем сеанс
sub info { # подпрограмма запроса информации
my ($OID, $caption) = @_; # параметры: код и имя объекта
my $response = $session->get_request($OID);
unless (defined($response)) { # если все нормально
print 'Ошибка запроса: ', $session->error();
} else { # выводим ответ:
printf "$caption/$OID:nt%sn", $response->{$OID};
}
}

В результате выполнения этой программы в ОС MS Windows будет выведена следующая информация:

sysDescr/1.3.6.1.2.1.1.1.0:
Hardware: x86 Family 6 Model 8 Stepping 6 AT/AT COMPATIBLE - Software: Windows 2000 Version 5.1
(Build 2600 Uniprocessor Free)
sysUpTime/1.3.6.1.2.1.1.3.0:
1 hour, 05:14.11

Для отслеживания состояния сети имеется много готовых программных продуктов различной сложности. Сбором и накоплением информации о работе сети и ее визуализацией занимаются основанные на SNMP системы: Big Sister (bigsister.sourceforge.net), Cricket (cricket.sourceforge.net) и MRTG (www.mrtg.org), которые распространяются свободно и написаны на языке Perl.

С момента своего создания язык Perl применялся системными администраторами для сетевого программирования. И постепенно было разработано неимоверное количество модулей для работы с самыми разными сетевыми сервисами. Даже упомянув лишь некоторые из них, можно составить представление о многообразии высококачественных решений сетевых задач, воплощенных в "жемчужных россыпях" хранилища модулей CPAN. В стандартном классе Net::NNTP реализован клиент новостных групп (телеконференций), располагающихся на многочисленных news-серверах. Perl-модули помогут сгенерировать документы для мобильных клиентов в формате WML (Wireless Markup Language). Модуль CDDB предоставляет интерфейс к сетевым базам данных по музыкальным компакт-дискам (Compact Disc DataBase). Имеются модули для работы с известными поисковыми системами: AltaVista, Google, Yahoo и с Интернет-магазинами Amazon и eBay.

В репозитарии CPAN можно найти модули для работы со всеми распространенными сетевыми протоколами: ARP (поиск физического адреса устройства по IP-адресу), DHCP (динамическое распределение IP-адресов), LDAP (доступ к каталогам типа Active Directory и NDS), NTP (запрос времени), RADIUS (авторизация пользователей), telnet и ssh (работа на удаленном терминале), VNC (сетевое управление компьютером) и многими другими. Причем Perl-модули могут использоваться для создания не только клиентских программ, но и серверов, которые можно встраивать в собственные приложения. И конечно же, есть огромное число модулей для работы с сервисами WWW, о которых пойдет речь в следующей лекции.

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

Оглавление книги


Генерация: 1.193. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз