Российский государственный гуманитарный университет
Опубликован: 15.08.2003 | Доступ: свободный | Студентов: 6518 / 1489 | Оценка: 3.91 / 3.79 | Длительность: 06:55:00
Лекция 3:

Введение в программирование на Perl

< Лекция 2 || Лекция 3: 1234 || Лекция 4 >

Файлы, каталоги, конвейеры, сокеты

При выполнении различных операций в CGI-скриптах часто приходится работать с файловой системой Web-узла. Perl обеспечивает довольно разнообразный инструментарий для такой работы. Условно его можно разбить на четыре части:

  • работа с файлами;
  • работа с каталогами;
  • работа с каналами (конвейеры);
  • работа с сетевыми ресурсами через сокеты.
Файлы

Для работы с файлами в Perl применяют несколько встроенных функций. Открывают файл функцией open. При этом для указания действий с записями файла используют префиксы:

open IN,"<test.txt"; 
# открыть файл на чтение

open IN,">test.txt"; 
# открыть файл на запись

open IN,"+<test.txt"; 
# открыть файл на чтение и запись

open IN,">>test.txt"; 
# открыть файл на модификацию (добавление)

Закрывают файл при помощи функции close:

close IN;

Для чтения записей из файла используют либо чтение потоком — <file>, либо функцию read:

while(<IN>)
  {
  print $_;
  }
  
read STDIN, $query, $ENV{CONTENT_LENGTH};

В первом случае данные построчно считываются из файла IN и распечатываются в поток стандартного вывода. Во втором случае из потока стандартного ввода, который тоже является файлом, считывается функцией read $ENV{CONTENT_LENGTH} байтов. Для обработки потока стандартного ввода CGI-скрипта подходит только второй способ, так как сервер не закрывает потока ввода, что приводит к бесконечному ожиданию ввода и разрыву соединения по timeout.

Каталоги

Для работы с каталогами используют ряд встроенных функций: opendir, readdir, closedir. Первая открывает дескриптор файла каталога, вторая позволяет читать записи из файла каталога, третья закрывает дескриптор файла каталога:

opendir DIR,"/usr/user";
while($_=readdir(DIR))
  {
  next if -d;
  print $_;
  }
closedir DIR;

В данном примере распечатываются названия файлов из каталога "/usr/users". При этом имена каталогов не распечатываются. Такое поведение скрипта определяется модификатором if в операторе next.

Каналы

Одним из замечательных свойств командных языков является возможность использования конвейеров. Они организуются путем перенаправления стандартного потока вывода одной программы в стандартный поток ввода другой. Иногда следует некоторые данные из скрипта профильтровать через такой конвейер, а потом снова ими воспользоваться. Открыть файл оператором типа

open FILTER,"<cat;more>";

нельзя. С точки зрения логики, при такой форме записи один дескриптор файла будет связан с разными потоками. Кроме того, поток стандартного ввода организует прием данных от сервера и уже занят. Возможность использования таких фильтров в Perl обеспечивает библиотека IPC. Запись при этом должна выглядеть следующим образом:

#!/usr/local/bin/perl
use IPC::Open2;
use FileHandle;
$pid = open2(\*RDR,\*WRD,"cat");
WRD->autoflush();
print WRD "test\n";
$got = <RDR>;
print "Это \$got:$got";

В данном случае для открытия канала связи между процессами используется функция open2. Ей необходимы три аргумента: указатель на дескриптор потока для чтения ( \*RDR ), указатель на дескриптор потока для записи ( \*WRD ) и строка внешней программы-фильтра ( "cat" ). Вместо cat можно указать любое множество команд, организованных в виде конвейера. Команда print посылает данные в этот конвейер, а команда "" считывает из него данные.

Работа с серверами Internet. Сокеты

Пусть и не очень часто, но все-таки приходится при разработке CGI-скриптов пользоваться возможностью обращения из скрипта к серверу, установленному на другом компьютере. При работе в сетях TCP/IP для этой цели используют библиотеку сокетов (Berkeley sockets) TCP/IP. Сокет — это пара "IP-адрес — номер порта". При программировании речь, конечно, будет идти о структуре данных, которая позволяет передать/принять данные с удаленного компьютера.

IP-адрес в сокете отвечает за доступ к определенному компьютеру в Internet. В общем случае IP-адреса закрепляются не за отдельными компьютерами, а за сетевыми интерфейсами. Один сетевой интерфейс может иметь несколько IP-адресов. Эта возможность используется при организации виртуальных Web-узлов.

Порт — это виртуальный канал приема/передачи данных, в котором происходит обслуживание приходящих из сети запросов. Этот канал обозначается цифрой. Первые 256 каналов — это WKS (Well Known Services, "хорошо известные" сервисы). Например, за HTTP-обменом закреплен 80-й порт, за FTP-обменом – 20-й и 21-й порты, за DNS (Domain Name System, служба доменных имен) – 53-й порт и т.д.

Порты бывают двух типов, TCP и UDP (User Data Protocol, пользовательский протокол данных), т.е. соответствуют типу транспортного протокола, который используется для передачи данных. Мы будем рассматривать в качестве примера именно TCP, т.к. HTTP-обмен использует только TCP-порты. Слово "порты" во множественном числе здесь употребляется не случайно. Дело в том, что только первоначальное обращение к HTTP-серверу происходит по 80-му порту. Для того чтобы обслуживать много запросов практически одновременно, сервер переназначает порт, и клиент, например, браузер, общается с сервером уже по другому порту.

Кроме TCP/IP существуют еще и другие виды сокетов, поэтому при программировании нужно указывать тип сокета. Ниже приведен пример обращения из скрипта к серверу HTTP:

#!/usr/local/bin/perl
use IO::Socket;
$remote = IO::Socket::INET->new(
Proto=>"tcp",
PeerAddr=>"localhost",
PeerPort=>"80"
) or die "No service";
$remote->autoflush(1);
print $remote "HEAD / HTTP/1.0\n\n";
while()
{
print;
}
-close $remote;

В данном примере используется пакет Socket из библиотеки IO (Interpretive Operation, работа в режиме интерпретации) (оператор use ). В третьей строчке примера происходит открытие дескриптора для сокета. Затем этот дескриптор применяется как обычный дескриптор файла, который открыт для записи и чтения.

Прежде чем писать данные в сокет, обычно отменяют буферизацию ( autoflush(1) — выталкиваем по одному байту). Делается это для того, чтобы данные сразу уходили на сервер. В противном случае сервер может разорвать соединение, не дождавшись запроса.

Оператор print демонстрирует запрос по протоколу HTTP 1.0 к HTTP-серверу. В этом запросе просто считывается документ из корня каталога HTTP-сервера. Обычно это файл index.html. Чтение отклика происходит в цикле while. После считывания отклика socket закрывается по функции -close.

Отложенное исполнение. Операция eval

Интерпретируемые языки программирования имеют две особенности, которых нет у компилируемых языков:

  • рекурсия;
  • отложенное исполнение.

С точки зрения эффективности кода это, конечно, не лучшие решения. Рекурсия может приводить к различного рода переполнениям, что, в свою очередь, вызывает крах программы, а отложенное исполнение не позволяет заранее оптимизировать код и в ряде случаев может приводить к рекурсивному вызову интерпретатора. Тем не менее изящность этих механизмов не может оставить программиста равнодушным.

Отложенное исполнение в Perl применяется в случае подстановки, в том числе рекурсивной

$sm =~ s/%(.{2})/pack('c',hex($1))/eg;

и в случае использования операции eval. Алгоритм работы этой операции достаточно прозрачен. В качестве аргумента в eval передается строка, которая затем рассматривается как Perl-программа. Для программирования из Web-браузера на Perl можно написать, например, такой скрипт:

#!/usr/local/bin/perl
read STDIN,$query,$ENV{CONTENT_LENGTH};
$query =~ s/%(.{2})/pack('c',hex($1))/ge;
$query =~ tr/+/ /ge;
$query =~ s/f=//;
eval $query;

Функция read в этом примере обеспечивает считывание данных из потока стандартного ввода скрипта. Операция рекурсивной подстановки позволяет преобразовать текст программ из формата form-urlencoded в ascii. Функция транслитерации tr заменяет символ "+" пробелом. Операция подстановки, следующая за транслитерацией, удаляет из кода программы имя поля и символ "=". Операция eval позволяет исполнить этот код. При этом предполагается, что данные передаются из формы с единственным полем типа textarea с именем "f".

Справедливости ради следует заметить, что в операции транслитерации кроме символа "+" нужно указать еще и другие символы, которые могут оказаться в коде программы. Например, если ввод кода осуществляется из браузера в среде MS-Windows, то при каждом переводе строки будет генерироваться символ "0D", который интерпретатор Perl для среды Unix не распознает.

Библиотеки

Программировать на Perl без применения дополнительных библиотек довольно сложно. В сети существует библиотека CPAN( http://www.perl.com/CPAN/ ). CPAN — это огромное хранилище полезного программного обеспечения. Для программирования CGI-скриптов в этой библиотеке имеются модули CGI-программирования. В последних версиях вместе с дистрибутивом Perl поставляется модуль CGI.pm. Но даже если этого модуля нет, его просто нужно скачать из CPAN.

Установка модуля в Perl довольно проста. Требуется выполнить следующие действия:

  1. модуль в архивированном виде переписывается из CPAN:
    edu>ftp ftp.perl.com
  2. создается временный каталог и модуль разархивируется в него:
    edu>gzip -d имя_модуля
  3. в каталоге находят файл Makefile.pl и выполняют генерацию файлов для сборки модуля:
    edu>perl Makefile.pl
  4. затем выполняют команды:
    edu>make; make test; make install

Теперь модуль установлен в Perl-каталог, и на него настроены все пути. С этого момента программы могут использовать функции из установленного модуля.

Включать функции из модуля в программу на Perl можно при помощи оператора use. Например, для получения имени текущего каталога используют функцию getcwd() из библиотеки Cwd:

#!/usr/local/bin/perl
use Cwd;
$dir = getcwd();
opendir DIR,$dir;
....
closedir DIR;

При организации конвейеров также применяются модули из библиотеки. Стандартные библиотеки обычно поставляются вместе с дистрибутивом Perl и устанавливаются при его сборке.

< Лекция 2 || Лекция 3: 1234 || Лекция 4 >