Выбрать главу

Даже если в большинстве случаев при сетевом программировании на 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_name\n"; # в строку

# результат: 208.201.239.36 www.perl.com

$address = inet_aton($ip_address); # и обратно

my $host_name = gethostbyaddr($address,AF_INET);# узнаем имя

print "$ip_address $host_name\n"; # по адресу

# результат: 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 "OK\n"; # посылаем ответ клиенту

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 "$message\n"; # отправляем его и

my $answer = <$socket>; # принимаем ответ

print "$answer"; # выводим ответ

close $socket; # и закрываем сокет

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