Даже если в большинстве случаев при сетевом программировании на 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) - фактических международных стандартов, на которые ориентируются разработчики сетевого программного обеспечения.