Ruby/Сети: различия между версиями
Содержимое удалено Содержимое добавлено
Нет описания правки |
Byzantine (обсуждение | вклад) орфография, викификатор |
||
Строка 2:
=== Как написать [[w:Троянская программа|троян]]? ===
Однажды один из студентов попросил меня рассказать о том, как создать простейшее клиент-серверное приложение на Ruby.
Строка 8 ⟶ 7 :
==== Построение серверной части ====
На руках у него уже была серверная часть программы, которая позволяла манипулировать удалённой файловой системой:
Строка 48 ⟶ 46 :
end</source>
Программка, конечно, хорошая, но сдаётся мне, что она не работает. Первое, на что следует обратить внимание,
<source lang="ruby">require 'socket'
Строка 100 ⟶ 98 :
* <code>cmd, arg = session.gets.chomp.split</code>
Данный код интересен тем, что в программе студента для его реализации задействовано аж три строчки. И всё потому, что он не знал о деталях присваивания при работе с массивами. В данном случае переменная <code>cmd</code> получает значение нулевого элемента массива, переменная <code>arg</code> —
Обратите внимание, что работа идёт с переменной <code>session</code>, а не <code>server</code>.
Строка 111 ⟶ 109 :
Для того, чтобы прекратить работу сервера необходимо нажать комбинацию клавиш <code>Ctrl+C</code> или <code>Ctrl+Break</code>. Команду отключения данный сервер не поддерживает. Команда <code>shutdown</code> относится к клиенту.
Несмотря на то, что данный сервер вполне рабочий, у него есть один существенный недостаток
<source lang="ruby">require 'gserver'
Строка 160 ⟶ 158 :
* <code>def serve(session)</code>
Метод <code>serve</code> ({{англ|serve}}
* <code>troyan = Troyan.new(31337)</code>
Строка 183 ⟶ 181 :
==== Построение клиентской части ====
Как мы уже видели выше, серверная часть полностью определяет функциональность всего клиент-серверного приложения. Клиентская же часть лишь принимает от пользователя запросы, пересылает их серверу и получает ответ, который передаёт пользователю.
Строка 254 ⟶ 251 :
troyan.join</source>
Была добавлена лишь одна команда (хотя самые внимательные могут заметить, что ещё и метод <code>.print</code> был заменён на <code>.puts</code>)
<source lang="ruby">require 'socket'
Строка 400 ⟶ 397 :
=== Как создать сетевой блокнот? ===
Идея написать подобную программу появилась после прочтения статьи [http://doci.nnm.ru/php_forall_/22.11.2006/sozdaem_svoj_onlajn_bloknot/ Создаём свой online-блокнот]. Продемонстрированная там программа предельно проста, но на её примере очень удобно показать работу с [[w:ERB|ERB]]. А учитывая тот факт, что ERB используется в составе инструментария [[w:Ruby on Rails|Ruby on Rails]], то ценность этой статьи становится очевидной.
==== Первое приближение ====
В первом приближении мы попытаемся реализовать ту же самую функциональность, что и описана в статье. Вот только [[w:PHP|PHP]] подразумевает наличие веб-сервера, который будет заниматься интерпретацией его команд. В нашем же примере мы самостоятельно поднимем веб-сервер (написанный на Ruby), чтобы не заморачиваться с настройкой стороннего.
Строка 469 ⟶ 464 :
==== Добавляем ERB ====
Теперь приступим к ERB. Это шаблонная библиотека, которая позволяет осуществлять вставку в произвольный текст любого Ruby-кода. Для этого имеются два основных тега:
Строка 519 ⟶ 513 :
==== Выносим ERB-шаблон во внешний файл ====
ERB-шаблон существенно портит красоту нашего Ruby-кода. Поэтому, решение вынести шаблон во внешний файл вполне оправдано. Тем более, что это позволит нам править ERB-шаблон отдельно от программы. Более того, внесенные в шаблон изменения будут вступать в силу без перезагрузки сервера.
Строка 550 ⟶ 543 :
==== ERB-шаблон превращается в ERB-сервлет ====
Если ERB-шаблон подключать, как ERB-сервлет, то программа существенно упрощается за счет того, что логику, которая отвечает за формирование данных можно вынести в шаблон. Чтобы это ощутить, достаточно взглянуть на новую версию нашей программы:
Строка 579 ⟶ 571 :
=== Гнёзда, которые свили не птицы ===
[[Файл:Гнезда.png|frame|center|Примерное содержание главы]]
=== Как пропинговать компьютер в сети? ===
Открываем новую серию статей, которые будут рассказывать про использование встроенных библиотек Ruby. Первая статья будет посвящена написанию утилиты <code>ping</code> (в очень упрощённой форме). Смотрим в стандартную библиотеку и обнаруживаем файлик <code>ping.rb</code>. Смотрим в него и обнаруживаем метод <code>pingecho</code>. Метод используется следующим образом:
Строка 610 ⟶ 600 :
=== Простейший датчик работы службы ===
Летним воскресным утром мне захотелось сделать что-то приятное и красивое… Я написал письмо в конференцию о моих светлых идеях, но не смог его отправить. [[w:SMTP|SMTP]]-сервер безбожно висел. И решило моё больное воображение написать программку, которая документировала бы подобные ситуации. В общем мне нужен был простейший документ (лог работы службы), который бы доказывал, что наши сетевые админы зря едят свой хлеб (а на самом деле я добрый). Для начала я определился с информацией, которая мне была нужна. А именно:
Строка 654 ⟶ 643 :
}</source>
Великолепно! Программа работает… но иногда зависает. И тогда меня посетила ещё одна мысль: на соединение отводить всего одну секунду (не уложился
<source lang="ruby">require 'timeout'
Строка 704 ⟶ 693 :
<code>user system total (real)</code>
Нам нужен только <code>real</code>. Всё остальное
<source lang="ruby">beachmark = Benchmark.measure{
Строка 745 ⟶ 734 :
=== Датчик обновления сайта ===
Ни для кого не секрет, что [[w:Сетевой администратор|админы]]
▲Ни для кого не секрет, что [[w:Сетевой администратор|админы]] — это жутко ленивый народ. Но начальство, как назло, не хочет платить деньги за просто так. Ему нужны отчёты! Представляю на ваш суд датчик обновления новостной ленты сайта. Для начала нужно как следует поставить себе задачу:
* Есть сайт, и админ его частенько обновляет.
Строка 754 ⟶ 742 :
* Новости располагаются на первой странице сайта.
Итак, для чего нам нужен датчик? Допустим вы
Итак, немного об алгоритме программы. Обычно новостей на главной странице строго определённое количество. На нашем тестовом сайте их ровно пять. У нас есть файл, в котором мы храним дату добавления новости и заголовок новости. Разделитель у нас может быть произвольным, но в качестве примера будет использован набор символов <code>' ^_^ '</code>. Вообще для данной задачи даже разделитель не очень-то и нужен (дата состоит из строго определённого количества символов и записывается в строго определённом формате), но универсальность превыше всего!
Строка 779 ⟶ 767 :
=== Как скачать HTML-страницу ===
Для скачивания HTML-страниц обычно используется протокол HTTP. Адрес страницы задаётся в виде URL. В Ruby существует несколько способов скачать страницу по протоколу HTTP. Начнём с самого древнего
▲Для скачивания HTML-страниц обычно используется протокол HTTP. Адрес страницы задаётся в виде URL. В Ruby существует несколько способов скачать страницу по протоколу HTTP. Начнём с самого древнего – класса <code>Net::HTTP</code> (древнее только Socket’ы, но про них мы умолчим). Для определённости мы будем скачивать этот учебник и сохранять его в виде файла <tt>RubyBook.html</tt>.
<source lang="ruby">require 'net/http'
Строка 801 ⟶ 788 :
==== Запрос заголовка ====
Во время скачивания передаётся не только сама страница (''тело сообщения'' или на {{англ|body}}), но и техническая информация (''заголовок'' или на {{англ|head}}). Мы ещё не раз будем свидетелями такого поведения в протоколах сети Интернет. В заголовке содержится информация об успешности запроса (код возврата), типе передаваемых данных, кодировке, HTTP-сервере и так далее. Для примера, мы будем производить HTTP-запрос и получать ответ только в виде заголовка. Запись заголовка в файл производить не будем, так как в реальной практике этот приём практически не используется. Сначала «потренируемся на кошках», то есть на классе <code>Net::HTTP</code>:
Строка 818 ⟶ 804 :
}</source>
Для этого достаточно присвоить результат метода <code>.get</code> двум переменным. Произойдёт присвоение списков, и в первую переменную попадет заголовок, а во вторую
Теперь рассмотрим, как выглядит чтение заголовков в методе <code>open</code> библиотеки <code>open-uri</code>:
Строка 826 ⟶ 812 :
p open('http://ru.wikibooks.org/wiki/Ruby').meta</source>
Замена метода <code>.read</code> на метод <code>.meta</code> позволяет нам дотянуться до заголовка. Заголовок имеет вид ассоциативного массива (объект класса <code>Hash</code>), где ключом является имя параметра (по стандарту [[w:MIME|MIME]]), а значением
<source lang="ruby">require 'open-uri'
Строка 838 ⟶ 824 :
==== Работа через прокси ====
[[w:Прокси-сервер|Прокси-сервер]]
▲[[w:Прокси-сервер|Прокси-сервер]] – это сервер, перенаправляющий запросы другим серверам. Обычно таковой используется для скрытия истинного [[w:IP-адрес|IP-адреса]] или для контроля за [[w:Трафик|трафиком]].
Необходимость HTTP-запроса через прокси возникает, когда соединение с целевым сервером напрямую невозможно (например, администратор сети посчитал, что соединение посредством шлюза даёт ему слишком мало возможностей контроля за трафиком). Использование подобного запроса маловероятно, но необходимо знать о возможности посылки HTTP-запроса через прокси. Начнём с класса <code>Net::HTTP::Proxy</code>:
Строка 864 ⟶ 849 :
=== Запускаем свой веб-сервер ===
Для того, чтобы создать простейший [[w:Веб-сервер|веб-сервер]] не нужно реализовывать протокол HTTP на уровне [[w:Сокет (программный интерфейс)|сокетов]]. Достаточно знать, какую библиотеку использовать. В нашем случае это будет библиотека [[w:WEBrick|WEBrick]] (http://www.webrick.org), которая уже включена в дистрибутив Ruby. Возможности библиотеки настолько широкие, что для их описания потребуется создание отдельного учебника. Мы рассмотрим лишь часть из них, зато на реальном жизненном примере.
Строка 895 ⟶ 879 :
Библиотека <code>WEBrick</code> реализована в виде модуля с одноимённым названием, поэтому до любого класса приходится «дотягиваться» через префикс: <code>WEBrick::</code>.
<code>HTTPServer</code>
Метод <code>.new</code> создаёт экземпляр класса <code>WEBrick::HTTPServer</code>. Методу передаётся два параметра (на самом деле
* <code>:DocumentRoot=>'public_html'</code> указывает на то, что веб-сервер будет просматривать директорию <code>./public_html</code> для выдачи html-страниц (и не только) по запросу. Если этот параметр не указывать, то сервер просто не будет работать.
Строка 1044 ⟶ 1028 :
* <code>bosses = { … }</code>
Создаётся ассоциативный массив, который будет использоваться при обработке данных. Ключом является имя «переключателя», а значением
* <code>require 'webrick'</code>
Строка 1077 ⟶ 1061 :
Запуск сервера.
Вот почти такую программу я и презентовал секретарше Анюте. «Почти» потому, что фамилии должны идти строго в определённом порядке (чего нельзя добиться в ассоциативном массиве), но для того, чтобы посмотреть реализацию веб-сервера
==== Сервлетки в рубиновом соусе ====
Мы уже неоднократно упоминали понятие сервлет, но особенно на нём не останавливались. Давайте сейчас рассмотрим типовые сервлеты, которые имеются в стандартной поставке <code>WEBrick</code>
Строка 1130 ⟶ 1113 :
end</source>
Немного поясню. Первая строчка
Функциональность CGI-сервлета описана в классе <code>WEBrick::HTTPServlet::CGIHandler</code>.
|