Иногда возникает необходимость из программы на перле соединиться с
другим сервером и передать/принять какую-нибудь информацию. Как
правило, возникает необходимость работать с протоколом HTTP, но поняв
основные принципы взаимодействия между двумя серверами и прочитав
спецификацию интересующего протокола, можно написать программу,
работающую практически через любой протокол. Далее мы рассмотрим
работу с протоколом HTTP.
Первое что нам понадобится это - сокеты (sockets). Сокет - это канал,
проложенный между сервером на котором запускается программа и
сервером, с которым мы хотим установить соединение. Для работы с
сокетами в перле есть модуль - Socket.
Для создания сокета используется функция socket. Формат ее таков:
socket(SOCK, DOMAIN, TYPE, PROTOCOL);
Данная функция открывает сокет и привязывает его к указателю SOCK.
* DOMAIN - это коммуникационный домен. Не нужно его путать с доменом
сервера с которым мы соединяемся. В нашем случае это будет
Internet домен (бывает еще Unix домен) а потому указываем: PF_INET
* TYPE - это тип сокета. Мы будем использовать SOCK_STREAM - этот
тип обеспечивает последовательный, надежный поток байтов. Так же
существуют Datagram socket и Raw socket, но о них как-нибудь в
другой раз.
* PROTOCOL - протокол, по которому будет устанавливаться соединение.
В нашем случае это tcp поэтому вместо PROTOCOL вставляем
следующее:
getprotobyname('tcp');
Помимо tcp можно использовать udp, ip и т.д. Функция getprotobyname
возвращает название протокола в более удобном для функции socket виде.
Итак создаем сокет:
Когда сокет готов, можно подключаться к конкретному серверу. Для этого
нам нужен адрес сервера и порт. Предварительно, необходимо сделать
следующее:
# Конвертирует имя сервера в бинарную последовательность.
$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 и забирает от туда главную страницу.
Если вы попробуете поменять значения переменной $host, то обнаружите,
что с некоторых серверов приходит сообщение об ошибке. Всему причиной
HTTP протокол и настройки Web-серверов. Более подробно о HTTP читайте
в статье "HTTP протокол". А пока о том как с этим бороться.
Дело в том, что в сети существует очень большое количество виртуальных
серверов, т.е. серверов с разными именами, но одним IP адресом.
Попробуйте например сделать Ping Любое_имя.narod.ru. Все они будут
иметь один IP адрес. А поскольку наш сокет фактически соединяется с IP
адресом, то мы и получаем сообщение об ошибке. Web-сервер того же
narod.ru просто не знает страницы какого из виртуальных серверов
показывать. Значит нужно объяснить ему это. Для этого существует
переменная HOST которая указывается в заголовке запроса. Т.е.
send (SOCK, "GET / HTTP/1.0nHOST:$hostnn", 0);
Подставив эту строчку в наш скрипт, мы получим уже более совершенную
программу. Так же, некоторые сервера в зависимости от браузера (а вы
еще не ощущаете себя им?) показывают разные версии сайтов. Встречается
такое крайне редко, но к этому нужно быть готовым. Используйте для них
переменную USER-AGENT.