div.main {margin-left: 20pt; margin-right: 20pt}
Perl и работа с сокетами
Иногда возникает необходимость из программы на перле
соединиться с другим сервером и передать/принять какую-нибудь информацию. Как
правило, возникает необходимость работать с протоколом 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
виде. Итак создаем сокет:
socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
Когда сокет готов, можно подключаться к конкретному серверу.
Для этого нам нужен адрес сервера и порт. Предварительно, необходимо сделать
следующее:
$iaddr = inet_aton($host); # Конвертирует имя сервера в бинарную последовательность.
$paddr = sockaddr_in($port, $iaddr); # Упаковывает все в понятную функции connect последовательность.
Теперь все готово и мы можем использовать функцию 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.0nn", 0);
@data=<SOCK>;
close(SOCK);
print @data;
Если вы попробуете поменять значения переменной $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.
Philip A. Koryaka e-mail:mailto:flp@mail.ru?subject=webmaster(cgi) Copyright
© 2001
|