Воскресенье, 05.05.2024, 07:43
Приветствую Вас Гость
Главная | Регистрация | Вход
Домик быта
Меню сайта
  • Главная страница
  • Информация о сайте
  • Обратная связь
  • Ремонт техники
  • Доска объявлений
  • Каталог статей
  • Каталог файлов
  • Каталог сайтов
  • Дневник
  • Форум
  • Гостевая книга
  • Всё для веб-мастера
  • Онлайн игры
  • Кино клипы музыка
  • Фотоальбомы
  • FAQ (вопрос/ответ)



  • Ремонт бытовой техники! Rambler's Top100

    Яндекс цитирования

    Рейтинг@Mail.ru

                 Полезные утилиты:
    SMS бесплатно С-Пб:

      Абонентам Билайн

      Абонентам МТС

      Абонентам Теле 2

      Абонентам Мегафон

      Абонентам Скайлинк

    Главная » Статьи » ПК Железо Soft » Вопрос-ответ "F1-Help" 2000-2002 г.

    Вопрос-ответ "F1-Help" 2002-20
    ЧАСТЬ 4.
    В этой части статьи мы рассмотрим не менее популярные, чем CGI-программирование, аспекты использования Perl - клиент-серверные приложения и программы для работы с базами данных.


    Технология витья "гнезд" и LWP-кулинария

    "Крылья... Ноги... Главное - хост!
    Во!..."
    c2002 cmapuk[0nline]

    Плетем гнезда. Стандартные инструменты Перл для работы с Сетью достаточно удобны и, в принципе, не нуждаются в надстройках. Исключение может составить разве что только модуль LWP. В этом разделе мы плавно пойдем от use Socket до use LWP; и таким образом попытаемся охватить все возможности сетевого Perl. Итак, стандартный модуль Socket.

    Socket - это модуль функционального типа. Описание всех его функций имеется в perldoc. Мы же рассмотрим сами принципы организации сетевых подключений. Не забывайте, что команда perldoc -f function - расскажет много интересного.

    use Socket; # Подключаем модуль
    $|++; # Отключаем буферизацию
    $request=<<REQ; # Составляем запрос в переменную $request
    GET /go.cgi?action=forum\&board=dummies HTTP/1.0
    User-Agent:LLamzilla Platinum 3000
    Referer:http://www.microsux.com
    Cookie:Da kakie nafig kuki!
    Accept:*/*
    Accept-Language:en;ru
    Accept-Charset:koi8-r

    REQ
    $protocol=getprotobyname('tcp');
    # Эта функция возвращает числовое обозначение по имени
    # протокола. Мы используем tcp протокол.
    # На TCP основаны все прикладные протоколы, например
    # HTTP, FTP, SMTP, POP3, и т.д.

    socket(SOCK,PF_INET,SOCK_S-TREAM,$protocol);
    # Открываем сокет с дескриптором SOCK(как файл в open).
    # Вторым параметром мы определяем либо сокет юниксов, либо сетевой
    # сокет. В данном случае - сетевой.
    # Третий параметр - тип передачи данных.
    # SOCK_STREAM-потоковый (для tcp), требующий подключения к удаленному
    # хосту. SOCK_DGRAM - не требует подключения, используется для передачи
    # данных отдельными пакетами(udp). Кстати, по большей части ICQ
    # работает как раз на udp.

    $iaddr=gethostbyname('perl.ru');
    # Получаем адрес по имени

    $port=80;
    $packed_addr=sockaddr_in-($port,$iaddr);
    # Упаковываем данные для подключения в
    # специальный формат(для функции connect())

    if(connect(SOCK,$packed_addr)){
      print SOCK $request;
      # Если подключение состоялось, посылаем запрос
      # и получаем ответ
      while(<SOCK>){
      push(@response,$_);
      }
    }else{
      print "Perl.ru в дауне =(";
    }
    close(SOCK);
    # Теперь в массиве @response у нас лежит ответ(примерно так):
    # 200 OK Found
    # Заголовки
    # ...
    # ...
    # Пустая строка
    # HTML-страница http://www.perl.ru/go.cgi?action=forum&board=dummies

    Для метода POST вся работа с сокетом аналогична. Изменяется только запрос.

    $request=<<REQ;
    POST /go.cgi HTTP/1.0
    User-Agent:LLamzilla Platinum 3000
    Referer:http://www.microsux.com
    Cookie:Da kakie nafig kuki!
    Accept:*/*
    Accept-Language:en;ru
    Accept-Charset:koi8-r
    Content-type:application/www-form-urlencoded
    Content-Length:26
    action=forum\&board=dummies
    REQ

    Конечно, данный способ менее всего удобен, но он позволяет контролировать весь процесс на всех стадиях его действия. Рассмотрим теперь этот же пример, но с использованием модуля IO::Socket;

    # Запрос тот же в $request
    $sock = IO::Socket::INET->new(PeerAddr => 'www.perl.ru',
      PeerPort => 80,
      Proto => 'tcp'
      Type => SOCK_STREAM);
    # Или так
    # $sock = IO::Socket::INET->new(PeerAddr => 'www.perl.ru:80');
    # $sock = IO::Socket::INET->new("XXX.XXX.XXX.XXX:80");
    # Параметры метода new() помогают ввести дополнительные опции
    # подключения, например Timeout.

    if($sock){
      print $sock $request;
      while(<$sock>){
      push(@response,$_);
      }
    }
    close($sock);
    # то же самое: if $sock значит, подключение состоялось
    # и мы отправляем данные, а потом принимаем
    # Для приема и отправки также существуют ф-ции send() и recv()

    Не сложнее, чем работа с файлами, правда?

    Стоит еще раз отметить: для UDP используется тип сокета SOCK_DGRAM и не требуется connect(), а для TCP - наоборот. В разделе "Чистая практика" мы еще вернемся к Socket и IO::Socket, а сейчас рассмотрим модуль LWP.
    LWP=lib-www-perl

    Этот модуль весьма популярен среди программистов. Он представляет собой удобный интерфейс к модулям Socket и IO::Socket. Cобственно, лучшего рассказа про LWP, чем perldoc lwpcook, найти сложно. Поэтому я просто возьму примеры оттуда и сделаю комментарии.

    Метод GET при использовании LWP-Simple

    use LWP::Simple;
    $doc = get("http://www.perl.ru");
    # Весь HTML в $doc
    getprint("http://www.perl.ru");
    # Вывод страницы сразу в STDOUT

    Запуск с консоли

    >perl -MLWP::Simple -e 'getprint "http://www.sn.no/libwww-perl/";'

    Распечатка в STDIN

    >perl -MLWP::Simple -e 'getstore "ftp://ftp.sunet.se/pub/lang/perl/CPAN/src/latest.tar.gz";,"perl.tar.gz"' 

    Скачать и сохранить файл как "perl.tar.gz"

    ######## В скрипте
    use LWP::UserAgent;
    $ua = LWP::UserAgent->new;
    $ua->agent("Gruzilla/10.0 Platinum"); # Типа кул броузер )
    $req = HTTP::Request->new(GET => 'http://www.perl.ru');

    # Модуль HTTP::Request сделан для удобства создания запросов
    $req->header('Accept' => 'text/html');

    # Теперь отправляем
    $res = $ua->request($req);

    # Проверим, все ли прошло ОК
    if ($res->is_success) {
      print $res->content;
      # Распечатка принятых данных
    } else {
      print "Error: " . $res->status_line . "\n";
    }
    Метод HEAD для LWP-Simple

    При методе HEAD данные не отправляются и не принимаются.

    Между клиентом и сервером идет обмен только заголовками.

    Это полезно, например, для проверки существования файлов на сервере и т.п.

    use LWP::Simple;
      if (@hdrs=head($url)) {
      # OK документ существует и доступен
      print join("\n",@hdrs);
      # Распечатаем заголовки
      }
    Метод POST (LWP-Simple нет)

    use LWP::UserAgent;
    $ua = LWP::UserAgent->new;
    # Составление запроса
    my $req = HTTP::Request->new(POST => 'http://www.someserver.com/script.cgi');
    $req->content_type('application/x-www-form-urlencoded');
    $req->content('param1=value1& param2=value2'); # Это данные якобы формы
    my $res = $ua->request($req); # Отправка
    print $res->as_string; # Распечатка результата отправки

    Еще вариант

    use HTTP::Request::Common qw(POST);
    use LWP::UserAgent;
    $ua = LWP::UserAgent->new;
    my $req = POST 'http://www.someserver.com/script.cgi',
    [ param1 => 'value1', param2 => value ];
    print $ua->request($req)->as_string;

    Используем PROXY-сервер

    use LWP::UserAgent;
    $ua = LWP::UserAgent->new;
    $ua->env_proxy; # Взять прокси-настройки из окружения
    # или вручную
    $ua->proxy(ftp => 'http://proxy.myorg.com');
    $ua->proxy(wais => 'http://proxy.myorg.com');
    my $req = HTTP::Request->new(GET => 'wais://www.xxx.com/');
    print $ua->request($req)->as_string;

    Если прокся с паролем

    use LWP::UserAgent;
    $ua = LWP::UserAgent->new;
    $ua->proxy(['http', 'ftp'] => 'http://proxy.myorg.com');
    $req = HTTP::Request->new('GET',"http://www.perl.com";);
    $req->proxy_authorization_basic("proxy_user", "proxy_password");
    $res = $ua->request($req);
    print $res->content if $res->is_success;

    Доступ к ресурсам, защищенным htaccess

    use LWP::UserAgent;
    $ua = LWP::UserAgent->new;
    $req = HTTP::Request->new(GET => 'http://www.linpro.no/secret/');
    $req->authorization_basic('login', 'password');
    print $ua->request($req)->as_string;

    А Куки?

    use LWP::UserAgent;
    use HTTP::Cookies;
    $ua = LWP::UserAgent->new;
    $ua->cookie_jar(HTTP::Cookies->new(file => "lwpcookies.txt",
    \t\t\t autosave => 1));
    # Теперь куки будут читаться/писаться в lwpcookies.txt
    # Далее уже запрос
    $res = $ua->request(HTTP::Request->new(GET => "http://www.yahoo.no";));
    print $res->status_line, "\n";

    Секьюрный протокол HTTPS (SSL)

    use LWP::UserAgent;
    my $ua = LWP::UserAgent->new;
    my $req = HTTP::Request->new(GET => 'https://www.helsinki.fi/');
    my $res = $ua->request($req);
    if ($res->is_success) {
      print $res->as_string;
    }else{
      print "Failed: ", $res->status_line, "\n";
    }
    # Код от обычного (для HTTP) мало чем отличается ;-)
    Создание зеркальных копий страниц

    use LWP::Simple;
    %mirrors = (
      'http://www.perl.ru/' => 'perl-ru.html',
      'http://www.perl.com/' => 'perl-com.html',
      'http://www.cpan.org' =>'cpan-org.html',
      'gopher://gopher.sn.no/' => 'gopher.html',
    ); while (($url, $localfile) = each(%mirrors)) {
      mirror($url, $localfile);
    }

    Доставка больших документов

    1-й вариант. Записываем данные в процессе скачивания в файл

    use LWP::UserAgent;
    $ua = LWP::UserAgent->new;
    my $req = HTTP::Request->new(GET => 'http://www.linpro.no/lwp/libwww-perl-5.46.tar.gz');
    $res = $ua->request($req, "libwww-perl.tar.gz");
    if ($res->is_success) {
      print "ok\n";
    }else{
      print $res->status_line, "\n";
    }

    2-й вариант. Вставка контролирующей подпрограммы в качестве второго аргумента $ua->request(). В этом варианте можно записывать скачиваемый файл по кусочкам, чтобы в случае обрыва связи потом его докачать.

    use LWP::UserAgent;
    $ua = LWP::UserAgent->new;
    $URL = 'ftp://ftp.unit.no/pub/rfc/rfc-index.txt';
    my $expected_length;
    my $bytes_received = 0;
    my $res =$ua->request(HTTP::Request->new(GET => $URL),
      sub {
      my($chunk, $res) = @_;
      $bytes_received += length($chunk);
      unless (defined $expected_length) {
      $expected_length = $res->content_length || 0;
      }
      if ($expected_length) {
      printf STDERR "%d%% - ",
      100 * $bytes_received / $expected_length;
      }
      print STDERR "$bytes_received bytes received\n";
      # В $chunk - текущие данные
      # print $chunk;
      }
    );
    print $res->status_line, "\n";

    Вот такой простой модуль. К нему мы еще вернемся, а сейчас перейдем к вопросам использования баз данных.
    От TXT до SQL

    Информация имеет силу, только когда ее можно сохранить.
    Перефразированный Карнеги ;-)

    Простые задачи. Perl, как и любой полноценный язык, предоставляет возможность сохранять/читать данные в/из различных источников, от файлов до SQL-образных баз данных. При таком многообразии главное - сделать правильный выбор. Для начала стоит определиться, с какими объемами данных будет работать программа, в какой форме эти данные и как часто будет использоваться программа. Для простейших задач подойдет и простой текстовый файл. Например, конфигурация программы.

    # config.dat
    # Коментарии
    # к конфигу
    DATADIR=/home/vasya/coolproga/datfiles
    EXITCODE=666
    MESSAGE=Hello, Master Pupkin!
    ...
    # end of config.dat
    В скрипте все это читаем:
    open(F,"config.dat");
    while($line=<F>){
      chomp $line;
      next if $line=~/^#/;
      # Пропустить строку комментариев
      ($var,$value)=split/=/,$line;
      $CONF{$var}=$value;
      # Конфиг собираем в хэш
    }
    close(F);

    Часто более удобным способом хранения информации являются простые базы данных - DBM-файлы. В этих файлах хранятся пары ключ/значение, а работа с данными производится через хэш, ассоциированный с DBM-файлом. DBM-базы бывают различных типов, зависящих обычно от операционной системы. Таблицу совместимости можно найти тут же - perldoc AnyDBM_File . Каждому типу соответствует свой Perl-модуль(DB_File, NDBM_File, etc). Связать хэш с базой можно разными способами - с помощью функций dbmopen или tie.

    use DB_File;
    dbmopen(%DATA, $dbfile)
    or die "Can't open $dbfile: $!";
    # Работаем с данными
    ...
    dbmclose(%DATA); # Завершаем работу с базой

    use NDBM_File;
    tie(%DATA, 'NDBM_File', $dbfile,O_CREAT|O_RDWR);
    # Работаем с данными
    ...
    untie(%DATA); # Завершаем работу с базой

    О работе этих функций - perldoc -f dbmopen и perldoc -f tie.

    Работа с хэшем DBM-базы не отличается от работы с обычным хэшем.

    В принципе, этой информации о DBM-файлах достаточно.

    Structured Query Language. Структурированный язык запросов, а попросту - SQL - это тема для отдельной статьи и только косвенно связана с Перл. Мы же рассмотрим способы взаимодействия с SQL-образными базами данных.

    Самым удобным интерфейсом к БД является модуль DBI (нет в стандартной поставке Перл). DBI - это основной модуль интерфейса, к которому необходимо присовокупить (гусары, молчать!) драйвер для соответствующей базы данных. Не надо пугаться! Драйвер - это всего-лишь Perl-модуль. Для каждого типа БД модуль-драйвер будет иметь название DBD::basename: DBD::mysql, DBD::InterBase, DBD::mSQL и т.п.

    Проще говоря, вам нужно просто установить два модуля: DBI и DBD::НазваниеБазы. Впоследствии, для других типов БД ставить DBI заново уже не требуется. Список имеющихся у вас драйверов можно получить так:

    use DBI;
    @driver_names = DBI->available_drivers;

    Теперь о работе с DBI.

    use DBI;
    $db = DBI->connect("dbi:mysql:database=Users-;mysql_socket=/tmp/mysql_socket.sock","login","password") || die "Database Connection ERROR $DBI::errstr";
    # Вот так мы подключимся к mysql-ной базе Users

    $db = DBI->connect("dbi:InterBase:database=/home/db/data.gdb;ib_dialect=3;ib_charset=win1251","-login","pass")|| die "$DBI::errstr";
    # А вот так - к базе формата InterBase
    ...
    # Завершение
    $db->disconnect();

    Ошибки базы данных пишутся в DBI::errstr, откуда их можно запросто прочитать =).

    Работа с данными после подключения происходит следующим образом.

    $req=$db->do("CREATE TABLE USERS .......... "); # простые SQL-команды
    $req=$db->do("DELETE FROM ORDERS"); # простые SQL- команды
    $req=$db->do("DROP TABLE USERS"); # простые SQL- команды
    # Более сложные команды типа SELECT, INSERT, и т.п.
    # требуют другого подхода
    $req=$db->prepare("SELECT NAMES FROM USERS");
    $req->execute || die "$DBI::errstr";
    $req->finish;

    Метод finish вызывается для освобождения памяти, если ваш скрипт производит несколько запросов.

    Для работы с данными в DBI имеется множество методов. Например:

    $rv = $db->do($query);
    # Просто запрос, результат которого окажется в $rv

    Для получения данных после запроса (после prepare и execute) имееются различные методы.

    @row = $req->fetchrow_array;
    # Массив полей строки после SELECT

    $req=$db->prepare("SELECT NAMES,LASTNAMES FROM USERS WHERE AGE>18");
    $req->execute || die "$DBI::errstr";
    while(@row=$req->fetchrow_array){
    print "Имя: $row[0], Фамилия $row[1]\n";
    }
    $req->finish;
    # Вот так, например, можно выбрать имена пользователей старше 18 лет.
    $row_ref = $req->fetchrow_arrayref;
    # Ссылка на массив полей строки после SELECT
    # То же самое, но обращение к данным будет производится как $row_ref->[0], $row_ref->[1].
    $hash_ref = $req->fetchrow_hashref;
    # Ссылка на хэш полей строки после SELECT
    # А вот так можно сложить выбранные строки в хэш, ссылкой на который будет
    # $hash_ref.
    # Если требуется выбрать одну строку, например случайного пользователя,
    # то достаточно будет такого действия:
    @row =$db->selectrow_array("SELECT NAME,LASTNAME FROM USERS ORDER BY RAND()");
    # Здесь не требуется prepare, execute и т.п.
    $row_ref = $db->selectrow_arrayref($query);
    # То же, но в виде ссылки
    $hash_ref = $db->selectrow_hashref($query);
    # или хэш-ссылки

    Можно сделать выборку в готовые переменные, которые выглядят нагляднее массивов и хэшей.

    Для этого нужно воспользоваться методом bind_columns и связать данные со ссылками на соответствующие переменные.

    $req=$db->prepare("SELECT NAMES,LASTNAMES FROM USERS WHERE AGE>18");
    $req->execute || die "$DBI::errstr";
    $req->bind_columns(\$Name, \$LastName);
    while($req->fetch()){
      print "Имя: $Name, Фамилия: $LastName\n";
    }
    $req->finish;

    Список всех методов подробно описан в документации к DBI (perldoc DBI). Описание модуля, содержащееся в комплекте поставки, занимает около 150 килобайт. Подробнее документацию вы вряд ли найдете. Также полную информацию можно найти здесь: dbi.perl.org. Стоит еще упомянуть о расширениях модуля DBI. Они носят названия вида DBIx::***. Найти их можно на search.cpan.org.

    Кроме модуля DBI существует масса отдельных модулей для разных типов БД. Например, Mysql - для MySQL, IBPerl - для InterBase. Однако, по моему мнению, DBI является самым удобным интерфейсом, а главное - он присутствует практически на всех хостингах.

    Почему я не стал рассказывать подробно о работе с базами данных? Дело в том, что большинство проблем, возникающих при программировании под БД, появляется вследствие незнания принципов работы с БД, различий между различными их видами, что выходит за рамки изучения Перл. Ликбез по этой теме требует написания отдельных статей с рассмотрением конкретных типов БД. Я же не ставил перед собой такую задачу. Все, что нужно для программирования Perl+DB, - это книга по языку SQL, документация к вашей БД и perldoc DBI.

    Небольшой совет. Запросы к БД следует составлять в отдельной переменной, и эту переменную передавать пераметром в do(), prepare(). Таким образом можно легко разобраться, если произойдет ошибка.

    $query="SELECT NAMES,LASTNAMES FROM USERS WHERE AGE>18";
    $req=$db->prepare($query);
    $req->execute || die "$DBI::errstr Запрос:$query";

    В следующей части статьи мы рассмотрим способы общения Perl-программ с пользователем, а именно - интерфейсы.

    По материалам журнала Компьютер Price (www.comprice.ru)

    Категория: Вопрос-ответ "F1-Help" 2000-2002 г. | Добавил: stachek36 (19.10.2008)
    Просмотров: 1771 | Рейтинг: 0.0/0
    Всего комментариев: 0
    Добавлять комментарии могут только зарегистрированные пользователи.
    [ Регистрация | Вход ]
    Форма входа
    Категории раздела
    Вопрос-ответ "F1-Help" 2000-2002 г. [7]
    Вопрос-ответ "F1-Help" 2003 г. [33]
    Вопрос-ответ "F1-Help" 2004 г. [24]
    Вопрос-ответ "F1-Help" 2005 г. [17]
    Вопрос-ответ "F1-Help" 2006 г. [49]
    Вопрос-ответ "F1-Help" 2007 г. [51]
    Вопрос-ответ "F1-Help" 2008 г. [44]
    Вопрос-ответ "F1-Help" 2009 г. [2]
    SOFT [3]
    Поиск
    Наш опрос
    Оцените мой сайт
    Всего ответов: 199
    Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Гоголь-Моголь
  • Статистика

    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0
    Мобайл сервис
    Сочи, ул. Московская, 19 Режим работы:
    Пн-Вс: 10.00-18.00
    Без выходных
    Контакты:
    +7(988) 238-00-94
    //stachek36.ucoz.ru
    e-mail: stachek36@mail.ru
    Copyright MyCorp © 2024Сайт создан в системе uCoz