Иногда есть потребность из программы на Perl соединиться с другими сервероми и передать или принять какую то информацию. Почти всегда возникает потребность работать с протоколом HTTP, но узнав принципы взаимодействия между серверами и прочитав спецификацию данного протокола, можно просто написать программу, работающую через любой протокол. В дальнейшем мы рассмотрим работу с протоколом HTTP.
Нам понадобится - сокеты (sockets). Сокет - канал, проложенный между сервером на котором запускается программа и сервером, с которым хотим установить соединение. Для работы с сокетами в Perl есть модуль - Socket.
Для создания сокета используют функцию socket. Формат у нее таков:
socket(SOCK, DOMAIN, TYPE, PROTOCOL);
Эта функция открывает сокет и привязывает его к указателю SOCK.
getprotobyname('tcp');
Помимо tcp можно также использовать udp, ip и т.д. Функция getprotobyname возвращает название протокола в удобном для функции socket виде.
Создаем сокет:
socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
Когда сокет готов, можно подключаться к определенному серверу. Для этого необходим адрес сервера и порт. Предварительно, необходимо сделать это:
# Конвертирует имя сервера в бинарную последовательность. $iaddr = inet_aton($host); # Упаковывает все в понятную функции connect последовательность. $paddr = sockaddr_in($port, $iaddr);
Все готово и можем использовать функцию connect:
connect(SOCK, $paddr);
После соединения с сервером, можем передавать и принимать определенную информацию. Рассмотрим процесс передачи и приема данных, подробнее, на примере соединения с Web-хостингом и получения с него определенного документа. Для отправки сообщения через сокет служит функция send:
send (SOCK, "То что шлем", 0);
Вместо 0 может быть один из этих флагов:
MSG_OOB - Посылать/получать данные для сокетов типа SOCK_STREAM
MSG_DONTROUTE - Посылать данные без маршрутизации пакетов. Используется диагностическими программами и процессами управляющими таблицами маршрутизации.
Для приема данных через сокет, используем стандартную операцию:
@data=<SOCK>;
После окончания связи, нужно закрыть сокет, при этом серверу говорится, что сеанс связи закончен. Для закрытия сокета есть функция close, которой нужно передать дескриптор сокета.
close(SOCK);
На последок пример рабочего кода. Программа соединяется с сервером www.perl.ru и забирает от туда главную страницу.
use Socket;
$host="www.perl.ru";
$port="80";
socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
$iaddr = inet_aton($host);
$paddr = sockaddr_in($port, $iaddr);
connect(SOCK, $paddr);
send (SOCK, "GET / HTTP/1.0\n\n", 0);
@data=<SOCK>;
close(SOCK);
print @data;
Если попробуете изменить значения переменной $host, то увидите, что с некоторых серверов поступает сообщение об ошибке. Всему причиной есть HTTP протокол и настройки Web-серверов. Подробнее о HTTP читайте в посте "HTTP протокол". Пока о том как с этим бороться.
Это происходит потому, что в сети существует большое количество виртуальных серверов, то есть серверов с различными именами, но одним IP. Попробуйте сделать Ping Любое_имя.narod.ru. Они будут иметь один IP адрес. А поскольку данный сокет фактически соединяется с IP , то и получаем известие об ошибке. Веб сервер того же narod.ru просто напросто не знает страницы какого из виртуальных серверов показать. Значит необходимо объяснить ему. Для этого есть переменная HOST которая указывается в заголовке запроса. Т.е.
send (SOCK, "GET / HTTP/1.0\nHOST:$host\n\n", 0);
Подставив данную строчку в наш скрипт, получим уже совершенную программу. Некоторые сервера в зависимости от браузера (вы еще не ощущаете себя браузером?) показывают различные версии сайтов. Встречается это очень крайне редко, но к этому нужно готовится. Используйте переменную USER-AGENT.
