На главную

Самопальный сервис

Создание 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

Использование SOAP в PHP5: http://www.zend.com/php5/articles/php5-SOAP.php

XMLRPC-EPI: http://xmlrpc-epi.sourceforge.net

Fase 4 XML-RPC: www.fase4.com/xmlrpc

phpRPC: http://sourceforge.net/projects/phprpc

phpxmlrpc: http://phpxmlrpc.sourceforge.net

XML-RPC Кейта Девинса: www.keithdevens.com/software/xmlrpc

 

(Администратор не несет ответственности (Автор Денис Евгеньевич)