Создание web-сервисов с использованием XML-RPC Все
в последнее время помешались на web-сервисах. Все больше
людей читают новости и форумы через RSS, поисковик
Google позволяет осуществлять запросы через
автоматические http-интерфейсы, интернет-платежи можно
также элементарным образом процессить через web-гейты.
Пришло время разобраться с тем, как все это работает и
каким образом можно организовать собственный сервис. Я
расскажу тебе о простом, стандартизованном и, должно
быть, самом популярном способе - об XML-RPC.
[какие еще сервисы?]
Вообще говоря, резонный вопрос :). В самом деле,
какие еще сервисы, о чем я? С появлением Интернета люди
стали создавать массу разнообразных продуктов: кто-то
написал первый форум, кто-то наколбасил сложную
распределенную вычислительную систему для обсчета
какого-нибудь научного опыта, кто-то решил сделать
поисковый центр, кто-то - организовать платежную систему
и так далее. У всех таких систем всегда есть, как
минимум, две взаимодействующие части: сервер и клиент.
Само собой, им для этого нужно как-то общаться. Ну,
скажем, вот твой браузер, когда ты читаешь форум на
xakep.ru, взаимодействует с web-сервером при помощи
протокола http; твой wm-keaper работает с платежным
центром WM при помощи какого-то другого прикладного
протокола. Казалось, все просто супер, но на практике не
совсем так.
Порой, расплывчатость описаний определенных
стандартов или их нечеткая реализация, приводила к
несовместимости отдельных систем. Кроме того, ребром
встала проблема взаимодействия между удаленными
системами, работающими под различными платформами. Каким
образом удобнее всего осуществить обмен информацией
между, скажем, какой-то программой, написанной для
Windows, и некоторым cgi-приложением под Unix? Масса
людей нашла ответ на этот вопрос в создании собственных,
порой, нелепых «протоколов». Но вот фигня - все они были
разными и абсолютно несовместимыми друг с другом. Это
было неудобно, да и городить каждый раз какое-то новое
решение - это маразм. Поэтому программисты решили
разработать единый стандарт, основанный на использовании
XML-представления запросов и ответов, который получил
название XML-RPC. RPC здесь расшифровывается так: Remote
Procedure Call (Удаленный Вызов Процедур). Чтобы было
понятнее, о чем я говорю, расскажу, какого рода сервисы
и системы можно создавать при помощи этой технологии.
[примеры сервисов]
Хороший пример - организация ботнета, управляемого по
http. Создавая десятки таких систем, люди обычно городят
какой-то огород с управлением. Кто-то использует HTTP
GET, кто-то передает запросы в виде отдельных
переменных, посланных POST'ом. Но все эти данные
обрабатываются в скрипте и это дополнительный геморрой,
особенно при мощной функциональности ботнета и его
распределенной структуре. Ну, представь, что для
регистрации новых ботов используется не один сервер, а
десяток. Нужно, во-первых, каким-то образом осуществлять
взаимодействие между ботами и этими серверами, а
во-вторых, обеспечить линковку между самими серверами
регистрации, чтобы вся информация была доступна из
единого «центра управления». Использование XML-RPC здесь
позволит, во-первых, сократить время на разработку
управляющей системы, во-вторых, легко подогнать и
переделать ее под любого другого бота. Стоит ли говорить
о максимальной совместимости и простоте такого подхода. |
Другой пример - скажем, автоматический перевод
текстов или проверка орфографии. При помощи
XML-RPС-запроса клиентское приложение (хоть плагин к
браузеру) отправляет текст для обработки и получает по
этому же протоколу мгновенно ответ от системы. К слову,
такие сервисы давным-давно уже есть в Сети, это не моя
больная фантазия. Все плюсы использования XML-RPC по
достоинству оценила целая куча разработчиков, которая
активно использует XML-RPC в своих системах. Ведь
реализация этого протокола есть практически для любого
языка программирования, и написать собственный
web-сервис совсем несложно. В этом мы с тобой сегодня
убедимся, но прежде давай я расскажу поподробнее, как
функционирует протокол, как он выглядит и как им
пользоваться.
[как это работает]
Следует понимать, что, с точки зрения сетевого
взаимодействия, обмен данными с web-сервисами
осуществляется при помощи протокола TCP и с
использованием стандартного метода POST HTTP. В
принципе, для web-сервера, обрабатывающего XML-RPC
запросы, это выглядит так же, как и обычная отправленная
методом POST форма: те же данные, передача их
выполняемому приложению, чтение его потока вывода и
выплевывание этих данных клиенту. Все, как и прежде, за
исключением того, что для транспортировки
непосредственно ДАННЫХ используется новый
протокол-надстройка над HTTP, который стоит на уровень
выше. Ведь все данные упаковываются в XML-представление
и в этом виде передаются по HTTP. Само приложение их
извлекает из тела XML-документа, некоторым способом их
обрабатывает и генерирует ответ, представленный в виде
XML-документа.
Как легко понять, после создания web-сервиса,
необходимо наколбасить и клиента, чтобы конечные
пользователи могли использовать этот сервис. Для этого
необходимо предоставить информацию об интерфейсе
сервиса, о его API. Эта информация, собственно, и делает
web-сервис доступным для всей Сети, предоставляя
сторонним разработчикам возможность легко и быстро
писать приложения для общения с твоим сервисом.
В настоящий момент уже даже существует специальный
язык WSDL (Web Services Description Language - Язык
Описания Web-Сервисов), который активно разрабатывается
и предназначен как раз для описания API-интерфейсов.
Думается, что при его использовании в некоторых случаях
разработку клиентов можно будет вообще автоматизировать.
Так же сервис обладает некоторой идентифицирующей его
информацией о типе и описании предоставляемой информации
- эти данные планируется использовать для формирования
единой базы данных с описанием всех сервисов Интернета.
[описание]
На самом деле, чтобы создавать web-сервисы и не надо
знать ничего о том, как работает XML-RPC. Ведь
использовать браузер можно, не читая спецификаций HTTP.
Но такие знания не будут лишними. Поэтому мы с тобой
сейчас разберемся с тем, как функционирует и устроен
протокол, рассмотрев на практике его работу. |
Запрос в XML-RPC состоит из двух частей: метода и
блока параметров. Каждому методу можно поставить в
условное соответствие некоторую функцию, определенную на
твоем языке программирования. Понятно, что параметры -
это передаваемые нашим функциям переменные. Параметры
могут быть разнотипые по своей природу: строки, целые
числа, массивы - поддерживаются основные структуры
данных. Помимо этого в XML-RPC присутствуют
дополнительные тэги для обработки ошибок, но я об этом
рассказывать не буду. Если это и впрямь тебе интересно,
стоит обратиться к документации на нашем диске. Весь
процесс взаимодействия при помощи XML-RPC между клиентом
и сервером начинается с клиентского запроса. Запрос
всегда содержит название метода, и, возможно, набор
необходимых параметров. Серверная часть анализирует
запрос, выполняет необходимые действия и возвращает
клиенту ответ, состоящий из набора интересующих данных.
По существу такое общение мало отличается от
локального вызова процедур. Все тоже самое: определяется
имя функции, фиксируется набор параметров, получается
результат работы.
Чтобы не быть голословным, рассмотрю конкретный
пример XML-RPC-запроса для сервера:
[пример запроса]
POST /xmlrpc.php HTTP/1.1
User-Agent: Cool XML-RPC Client v X.X
Host: cool.xml.rpc.service.com
Content-type: text/xml
<?xml version="1.0"?>
<methodCall>
<methodName>getNumberBots</methodName>
<params>
<param><value><int>43</int></value></param>
</params>
</methodCall>
Ответ web-сервиса выглядит примерно следующим
образом:
[ответ web-сервиса]
HTTP/1.1 200 OK
Date: Mon, 10 Oct 2005 19:36:56 GMT
Server: Apache/1.3.29 (Unix)
X-Powered-By: PHP/5.0.1
Content-Length: 138
Connection: close
Content-Type: text/xml; charset=UTF-8
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param>
<value><int>16</int></value>
</param>
</params>
</methodResponse>
Думаю, на этом можно завершить рассказ о самом
протоколе XML-RPC. Ты получил примерное представление о
нем, и этого достаточно для дальнейшего понимания
статьи. Тем более, что всю работу по составлению,
парсингу запросов и ответов, берут на себя различные
расширения, которые можно найти почти для любого языка
программирования. Они поставляются в самых разнообразных
вариантах - в виде dll, PHP-классов и модулей, для
установки которых нужно пересобирать интерпретатор
твоего языка. Мы для простоты и удобства будем
использовать в наших разработках PHP. В качестве
реализации XML-RPC я выбрал пакет, поставляемый через
PEAR:
http://pear.php.net/package/XML_RPC. Это быстро и
удобно. Если тебе интересно узнать об альтернативных
пакетах, то почитать об этом можно в соответствующей
врезке.
[свой сервис]
Сейчас настало время написать свой собственный
web-сервис. Давай с тобой наколбасим для начала
элементарный сервис с одним-единственным методом.
Что-нибудь учебное. Пусть, скажем, наш сервис получает
единственный параметр - дату и возвращает в ответ число
зарегистрированных в этот день ботов, осуществляя
соответствующий запрос с базе данных. |
Первым делом установки PEAR-расширение XML_RPC: $
pear install XML_RPC
Или можно просто руками скачать с сайта архив с
нужными скриптами. Затем уже можно приступать к
написанию серверной части нашего приложения. Любое
описание сервиса всегда начинается с подключения файла
Server.php, в котором находится описание всех
необходимых нам служебных классов. Поскольку я не
пользовался pear install, а просто скопировал исходники
в папку со скриптом, то у меня это выглядит вот так:
require_once 'XML_RPC-1.4.3/Server.php';
Затем необходимо определить функцию, которая будет
выполнять заданное действие - считать ботов, я назвал ее
NumBots. Я приведу ее код и прокомментирую его чуть
позже:
function NumBots($params) {
$param = $params->getParam(0);
if (!XML_RPC_Value::isValue($param)) {
return $param;
}
$re=mysql_query("select * from bots where
date_reg='$param->scalarval()'");
$rn=mysql_num_rows($re);
$val = new XML_RPC_Value($rn, 'int');
return new XML_RPC_Response($val);
}
Легко понять, что $params - это переменная класса,
получение параметров осуществляется при помощи метода
getParam(). Затем происходит проверка на корректность
полученных данных, составляется элементарный запрос,
считается количество возвращенных записей, создается
новая переменная класса XML_RPC_Value, а затем
возвращается ответ сервера.
После описания процедуры необходимо создать экземпляр
XML_RPC_Server и сопоставить символическому методу
numberOfBots нашу функцию NumBots. Делается это так:
$server = new XML_RPC_Server(
array(
'numberOfBots' =>
array(
'function' => 'NumBots'
)
));
?>
Вот, в общем-то, и все :). Согласись, все чрезвычайно
просто. Но чтобы придать законченность нашей системе,
необходимо написать еще клиентскую часть. Первая строка
у всех клиентов одинаковая, нужно подключить файл
RPC.php:
require_once 'XML_RPC-1.4.3/RPC.php';
Затем из передаваемой GET'ом переменной $_GET[date_r]
нужно сделать массив переменных XML_RPC_Value:
$params = array(new XML_RPC_Value($_GET[date_r],
'string'));
Обрати внимание, что конструктор этого класса первым
параметром принимает сами данные, а во втором
указывается тип - в нашем случае - строка string. После
этого создается RPC-сообщение, которое вызывает метод,
передавая ему параметры $params:
$msg = new XML_RPC_Message('numberOfBots', $params);
Затем необходимо создать клиента и отослать наше
сообщение:
$cli = new XML_RPC_Client('/te/se.php',
'ired.inins.ru');
$resp = $cli->send($msg);
После этого происходит обработка ошибок:
if (!$resp) {
echo 'Ошибка связи:' . $cli->errstr;
exit;
}
if (!$resp->faultCode()) { # Не случилось ошибок
$val = $resp->value();
echo 'За '.$_GET[date_r].' зарегистрировано '.$val->scalarval().'
ботов';
} else {
echo 'Код ошибки: ' . $resp->faultCode() . "\n";
echo 'Причина ошибки: ' . $resp->faultString() . "\n"; |
} Вот так выглядит создание элементарного сервиса
и клиента к нему.
[структуры посложнее]
Теперь расскажу о том, каким образом возможно
транспортировать нескалярные переменные вроде массивов и
структура данных. Ведь действительно, очень часто в этом
есть огромная необходимость. Ну, скажем, в нашей
воображаемой распределенной системе управления ботнетом
может появиться необходимость получить всю информацию о
ботах, зарегистрированных за определенную дату на
определенном сервере, а не просто пересчитать их, как мы
это делали в примере выше. Сейчас я покажу тебе, каким
образом сервер может ответить клиенту массивом данных.
Новая функция, которая будет ассоциирована с методом
ViewBotInfo, который мы добавим к нашему сервису,
называется BotInfo:
[функция, которая возвращает массив структур с
информацией о ботах]
function BotInfro($params) {
$param = $params->getParam(0);
$re=mysql_query("select * from bots where
date_reg='$param->scalarval()'");
$val=new XML_RPC_Value();
$bots=array();
$i=0;
while($res=mysql_fetch_array($re)) {
$bots[$i]=new XML_RPC_Value(array(
"ip" => new XML_RPC_Value("$res[ip]"),
"country" => new XML_RPC_Value("$res[country]"),
"date_r" => new XML_RPC_Value("$res[date_r]")), "struct");
$i++;
}
$val->addArray($bots);
return new XML_RPC_Response($val);
}
Видно, что в первых двух строчках функции я получаю
параметр - дату для выборки и создаю SQL-запрос к базе
данных. Затем создается переменная $val класса
XML_RPC_Value, инициализируется массив $bots c ботами.
После этого в цикле по всем возвращенным запросом
записям таблицы этот массив заполняется структурами,
несущими информацию о ботах. Разумеется, все это
условно, реальные структуры могут быть значительно
сложнее, но общий принцип именно такой.
После этого цикла, когда создан «массив ботов»,
необходимо из этого массива изготовить переменную класса
XML_RPC_Value. Для чего к уже созданному объекту, при
помощи метода addArray(), добавляется наш массив.
Клиентская сторона, которую так же необходимо
реализовать, работает аналогично уже разобранному
случаю. С той лишь разницей, что $val = $resp->value() -
это не массив в привычном понимании этого слова. Это
переменная XML_RPC_Value, а доступ к элементам массива
должен осуществляться при помощи метода arraymem().
Например, $val->arraymem(0) вернет переменную
XML_RPC_Value элемента с нулевым индексом. В нашем
случае это - структура с информацией о ботах. Получить
конкретные значения полей можно следующим образом: $val->arraymem(0)->structmem("ip")->scalarval().
[выводы]
Может показаться, что использование этой системы
подразумевает недюжинный объектный геморрой. И хоть это
может сначала показаться громоздким и неудобным, но это
не так. Стоит поработать с системой хотя бы 15 минут,
как все становится понятно, привычно и удобно.
Если же ты на дух не переносишь объектный подход,
советую обратиться к другим реализациям XML_RPC.
Информацию о них ты найдешь в соответствующей врезке.
Все напечатанные в статье скрипты, дополненные и
дописанные, оформленные в виде полноценного тестового
примера, ты отыщешь на нашем диске. Там же найдется
масса документации, а также все упомянутые в статье
реализации XML_RPC. |
[альтернативные пакеты] Вообще, реализация XML_RPC
есть для кучи самых разных языков и в самых разных
вариантах. Полный список всех разработок можно найти на
сайте www.xplrpc.com, на странице implementations. Я же
расскажу об основных разработках, предназначенных для
использования совместно с PHP.
- phpRPC (http://phprpc.sourceforge.net).
Это крутой и навороченный по функциональности PHP-класс.
Программисты, которые его создали, решили не
ограничивать себя только лишь генерацией и парсингом
XML_RPC-транзакций. Их детище предоставляет возможности
по взаимодействию с «абстрактными», удаленными базами
данных, через интерфейс XML_RPC. Вообще, проект
создается для совместного использования с Xoops.
- XMLRPC-EPI (http://xmlrpc-epi.sourceforge.net).
Этот пакет представляет собой класс, написанный на C++
и, само собой, для установки необходимо иметь
достаточные права и доступ к компилятору - надо будет
пересобирать PHP. Само приложение не поражает
функциональностью: оно лишь парсит запросы и ответы
XML-RPC, но не занимается их передачей. Использовать эту
штуку без конкретной и осознанной необходимости в
компилируемом решении я бы не советовал.
- XML-RPC Client/Server Кейта
Девинса(www.keithdevens.com/software/xmlrpc). Чувак по
имени Кейт написал, наверное, самый удобный для новичков
пакет для работы с XML-RPC. Все предельно просто: есть
набор описанных функций, которые подключаются к твоим
сценариям и могут легко использоваться. Никакой возни с
объектами - все просто и линейно. Можно посоветовать
этот пакет тем, кого пугают прелести ООП.
Шило на мыло
Если ты следишь за технологиями, то наверняка слышал
о такой вещи, как стандарт SOAP (Simple Object Access
Protocol). Эта технология служит для «упаковки»
разнообразных данных при обмене между двумя узлами
какой-то системы. SOAP - это XML-протокол, работающий
поверх одного из старых web-протоколов, чаще всего -
HTTP. В некотором смысле, SOAP - это конкурирующий с
XML-RPC стандарт, которому даже хотят дать рекомендации
W3C. Учитывая, что этому процессу всячески помогает
Майкрософт, это уже не за горами.
SOAP значительно сложнее XML-RPC, об этом адекватно
можно судить просто по объему спецификации: документ,
описывающий работу SOAP, весит примерно в 10 раз больше,
чем описание XML-RPC.
Сравнивать эти стандарты - занятие неблагодарное,
однако если тебе интересно почитать об этом, советую
обратиться к статье XML-RPC vs SOAP (http://weblog.masukomi.org/writings/xml-rpc_vs_soap.htm).
Вообще, считается, что SOAP - это будущее разработок.
Однако не стоит думать, что XML-RPC - гнилая вещь. Дело
в том, что любой XML-RPC запрос может быть легко
переконвертирован в соответствующее SOAP-приложение при
помощи XSLT. XXXXXXXXXXXXXXXXXXXXX
WWW
Статья XML-RPC vs SOAP:
http://weblog.masukomi.org/writings/xml-rpc_vs_soap.htm |
(Администратор не несет ответственности (Автор Денис
Евгеньевич)
|