Saturday, December 29, 2007

What is XML-RPC?

XML-RPC is a standard network protocol that computers can use to talk to each other in a remote procedure call fashion. Remote procedure call essentially means that a program on one computer runs a program on another computer. But a simpler way of looking at this kind of network protocol is just that you have clients and servers. A client makes individual isolated requests of a server. A server sits around waiting for a request to arrive from some client, does what the request asks, and sends a response. It then goes back to waiting for the next request.


Here are some examples of remote procedure call (RPC) style communications:

There is a server that can measure atmospheric temperature. A client anywhere in the world can ask the server at any time what the temperature is. The "what temperature is it?" request and the "the temperature is..." response constitute an RPC transaction.
There is a server that can turn a light on or off. A client can tell the server to turn the light on. A request to turn the light on and the acknowledgement that the light has been turned on constitute an RPC transaction.
There is a server that knows the phone numbers of a million people. A client can supply a name and get back the phone number of the named person.
A network of 1000 computers is used to search millions of web pages. A dispatcher computer is a client and the rest are servers. The dispatcher sends each of the servers one URL at a time and some search terms. The server responds with yes or no as to whether the page with that URL contains the search terms. The dispatcher keeps a list of the URLs that match. Each of the requests to search a particular URL is an RPC transaction.
Here are some kinds of communication that are not RPC:

A long-lived connection such as an SSH login session.
A high volume transfer such as an FTP download.
A one-way transmission such as a UDP packet.
A dialogue such as an SMTP (mail) transaction.
The original RPC protocol is the ONC RPC protocol -- the one that NFS (the network fileystem protocol) uses. It's often called "Sun RPC" because Sun invented and promulgated it. The ONC RPC protocol is layered over UDP or sometimes TCP and uses a machine-friendly bits and bytes format, just like the TCP/IP layers under it.

XML-RPC differs from ONC RPC in that it encodes the information in the requests and responses in XML. That means they are human friendly -- XML is human-readable text, so a human can readily see what's going on from a network trace and quickly write code to create and decipher XML-RPC streams. Of course, the tradeoff is that XML-RPC uses way more network and computation resources than ONC RPC. Because XML-RPC is meant to be used for relatively small and infrequent transactions, this is thought not to matter.

In XML-RPC, the aforementioned XML is transported via HTTP (the protocol whose principal purpose is to implement web serving -- web browsing is a form of RPC, after all). HTTP is normally carried over TCP, which is carried over IP.

There are lots of servers in the world that use the XML-RPC protocol and lots of programs and programming libraries from which people can build XML-RPC-based servers and clients.

There are also other HTTP-based RPC protocols. SOAP and CORBA are the most famous. REST-RPC is a more recent entry.

For more information on XML-RPC, see The XML-RPC web site and The XML-RPC Howto. The latter includes information (with examples) on implementing XML-RPC clients and servers in languages other than C and C++, which is all that is covered in this document.

How Does XML-RPC For C/C++ Help with XML-RPC?
The function libraries in XML-RPC For C/C++ (Xmlrpc-c) let you write a program that makes XML-RPC calls (a client) or executes XML-RPC calls (a server program) at any of various levels of understanding of the XML-RPC protocol.

Here are some examples of client and server code.

The Xmlrpc-c Function Libraries
This is a list of the function libraries Xmlrpc-c provides, with links to the manual for each.

There are two sets of libraries -- C and C++. You can of course use the C libraries in a C++ program, but you cannot in general mix the two -- you use either the C Xmlrpc-c facilities or the C++ Xmlrpc-c facilities. The C++ libraries depend heavily on the C libraries, but apart from having to install and link to the C libraries, you won't see that from the outside.

The C++ libraries were all new in Xmlrpc-c 1.03 (June 2005).

There is an older C++ facility, which is just a thin wrapper around the C libraries. We do not document it in this manual or recommend it, but it remains part of Xmlrpc-c for backward compatibility. This library consists in the header file xmlrpc-c/oldcppwrapper.hpp (fka XmlRpcCpp.h) and the library libxmlrpc_cpp.

C Libraries
libxmlrpc - general facilities
libxmlrpc_client - facilities for implementing a client
libxmlrpc_server - facilities for implementing a server — facilities which are independent of the transport mechanism.
libxmlrpc_server_abyss - facilities for implementing a server, based on an Abyss HTTP server.
libxmlrpc_abyss - The Abyss server software.
libxmlrpc_server_cgi - facilities for implementing a server via CGI scripts under an arbitrary HTTP server (i.e. web server).
C++ Libraries
libxmlrpc++ - general facilities
libxmlrpc_client++ - facilities for implementing a client
libxmlrpc_server++ - facilities for implementing a server — facilities which are independent of the transport mechanism.
libxmlrpc_server_abyss++ - facilities for implementing a server, based on an abyss HTTP server.
libxmlrpc_server_pstream++ - facilities for implementing a pseudo-XML-RPC server that uses a packet stream in place of HTTP and has multi-RPC client/server connections.
Utility Programs
Xmlrpc-c comes with a few utility programs that you can use to diagnose problems or learn about XML-RPC or Xmlrpc-c. These programs double as examples of how to use the Xmlrpc-c function libraries.

Because the utility programs are not essential to the package, the default install tools don't install them at all. The builder does build them, though, and if you build Xmlrpc-c from source, you will find them all in the tools/ directory.

You'll also find more complete documentation there.

xmlrpc
xmlrpc is a general purpose XML-RPC client program. It performs one XML-RPC call, which you describe in its command line arguments.

Example:


$ xmlrpc http://localhost:8080/RPC2 sample.add i/3 i/5


This makes a call to the XML-RPC server at the indicated URL, for the method named "sample.add", with two arguments: the integer 3 and the integer 5.
xmlrpc prints to Standard Output the result of the call, which it gets back from the server.

You can abbreviate the URL; xmlrpc assumes "http://" and "/RPC2":


$ xmlrpc localhost:8080 sample.add i/3 i/5
Result:
Integer: 8


The port number defaults to 80, so you can abbreviate even more:


$ xmlrpc localhost sample.add i/3 i/5


String arguments look like this:


$ xmlrpc http://www.xmlrpc.com/RPC2 method_that_takes_string s/hello


If you don't include a type specifier such as "i/" or "s/", xmlrpc assumes "s/". So you can use this shortcut, equivalent to the above:


$ xmlrpc http://www.xmlrpc.com/RPC2 method_that_takes_string hello


Each argument to xmlrpc describes on XML-RPC parameter. So in a typical command shell, the following would make an XML-RPC call with two paramters: "hello" and "see you later":


$ xmlrpc http://www.xmlrpc.com/RPC2 mymethod s/hello "s/see you later"


Compound values for parameters look the following, except that these aren't implemented yet. Only "i/" and "s/" are implemented right now.

Note that this is an example of a Bourne shell command, so some of the characters (most notably the quotation marks) are part of the shell language, not the xmlrpc syntax.


$ xmlrpc http://www.oreillynet.com/meerkat/xml-rpc/server.php \
meerkat.getItems \
"struct/{search:linux,descriptions:i/76,time_period:12hour}"
Result:
Array:
Struct:
title: String: DatabaseJournal: OpenEdge-Based Finance ...
link: String: http://linuxtoday.com/news_story.php3?ltsn=...
description: String: "Finance application with embedded ...
Struct:
title: ...
link: ...
description: ...




$ xmlrpc localhost:8080 array_processing_method \
"array/(i/3,i/49,s/hello,array/(i/-10,i/-9))"


xmlrpc is implemented using the Xmlrpc-c client library, but its function is not in any way tied to Xmlrpc-c. It makes a standard XML-RPC call and does not know or care whether the server is implemented with Xmlrpc-c or not.

For extra diagnostic information, use the XMLRPC_TRACE_XML environment variable so you can see the XML that goes back and forth to perform the call. (This is not specifically xmlrpc function -- it's tracing function that's automatically there because xmlrpc uses libxmlrpc_client).

Alternatives
This section describes some alternatives to using XML-RPC For C/C++.

Other Progamming Languages
There are plenty of facilities to help you create XML-RPC clients and servers in a language other than C or C++. Search on Freshmeat.

It is worth mentioning that with some of these other-language facilities, the client or server is way slower than with XML-RPC for C/C++, due to the nature of the language. For example, I have used the Perl RPC::XML modules from CPAN and found a client program that takes 50 milliseconds to run when written with XML-RPC For C And C++ takes 2000 milliseconds to run when done with RPC::XML::Client.

In the case of Perl, there is a middle ground. The RPC::Xmlrpc_c modules from CPAN are based on Perl extensions that use the libraries of XML-RPC For C And C++. One reason RPC::XML is so slow is that it is built on top of a stack about 6 layers high, each one implemented in interpreted Perl. With RPC::Xmlrpc_c, all those layers except the top are implemented as executable machine code, efficiently compiled from C, so you have the same ease of Perl coding, without the slowness.

RPC::Xmlrpc_c is much younger than RPC::XML, so doesn't have many features, and in fact does not include any server facilities. But you could add missing features yourself (and, ideally, submit them for inclusion in the RPC::Xmlrpc_c package on CPAN, so others can use them).

RPC::Xmlrpc_c was new in December 2006 and needs XML-RPC For C And C++ Release 1.08 or better.

In other interpreted languages, the same hybrid may be possible -- replacing slow interpreted code with executable XML-RPC libraries.

Apache Module
You can make a nice XML-RPC server based on an Apache HTTP server (which may or may not simultaneously be a regular web server) using an Apache module. mod_xmlrpc is one such module. mod_xmlrpc is actually built on Xmlrpc-c, so you can use the same method code as you do for other Xmlrpc-c-based implementations

An even simpler, though less efficient and more limited way to make an XML-RPC server out of an Apache server is to do it via a CGI script. That script can be written in a variety of languages, but if you write it in C, you can use Xmlrpc-c's libxmlrpc_server_cgi library.

Other RPC Protocols
SOAP and CORBA are common alternatives to XML-RPC. Lots of expensive commercial software helps you use those. There is more to know and more you can do with them.

REST-RPC was invented in 2006 and was meant to be superior to XML-RPC for at least some things. It is easier to use in many ways than XML-RPC. Like XML-RPC, it uses HTTP, and like XML-RPC an RPC's result is XML. But unlike XML-RPC, a call is not XML. It is encoded entirely in the query part of a URL. (Example: http:/test.rest-rpc.org/?_function=GetCart&cart=1563). In the result, there are no inherent data types; server and client agree on those separately. The Xins project has more information.

Appendices
Introductory Examples
Here, to show you what Xmlrpc-c is, we present example code (almost an entire C program) for a simple XML-RPC client that exploits the Xmlrpc-c libraries, and a corresponding simple XML-RPC server.

You can find complete working versions of these, and lots of other examples in the examples/ directory in the Xmlrpc-c source tree.

In these examples, the service to be provided is adding of two numbers. You wouldn't do this with RPC in real life, of course, because a program can add two numbers without the help of a remote server. This is just to demonstrate the concept.

Table Of Contents
Small C Client Example
Small C Server Example
CGI C Server Example
Small C++ Server Example
Small C++ Client Example
Small C Client Example
Here is an example of C code that implements an XML-RPC client using the highest level facilities of Xmlrpc-c. This client sends a request to add 5 and 7 together to an XMLRPC-C server that is designed to provide the service of adding numbers.


#include
#include

#include "config.h" /* information about this build environment */

#define NAME "XML-RPC C Test Client"
#define VERSION "1.0"

int
main(int const argc,
const char ** const argv) {

xmlrpc_env env;
xmlrpc_value * resultP;
int sum;
char * const url = "http://localhost:8080/RPC2";
char * const methodName = "sample.add";

/* Initialize our error-handling environment. */
xmlrpc_env_init(&env);

/* Start up our XML-RPC client library. */
xmlrpc_client_init2(&env, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, NULL, 0);
die_if_fault_occurred(&env);

/* Make the remote procedure call */
resultP = xmlrpc_client_call(&env, url, methodName,
"(ii)", (xmlrpc_int32) 5, (xmlrpc_int32) 7);
die_if_fault_occurred(&env);

/* Get our state name and print it out. */
xmlrpc_parse_value(&env, resultP, "i", &sum);
die_if_fault_occurred(&env);
printf("The sum is %d\n", sum);

/* Dispose of our result value. */
xmlrpc_DECREF(resultP);

/* Clean up our error-handling environment. */
xmlrpc_env_clean(&env);

/* Shutdown our XML-RPC client library. */
xmlrpc_client_cleanup();

return 0;
}



Small C Server Example
Now, here is code that implements an XML-RPC server that provides the number-adding service from the previous section.


#include
#include
#include

static xmlrpc_value *
sample_add(xmlrpc_env * const envP,
xmlrpc_value * const paramArrayP,
void * const serverContext) {

xmlrpc_int32 x, y, z;

/* Parse our argument array. */
xmlrpc_parse_value(envP, paramArrayP, "(ii)", &x, &y);
if (env->fault_occurred)
return NULL;

/* Add our two numbers. */
z = x + y;

/* Return our result. */
return xmlrpc_build_value(envP, "i", z);
}



int
main (int const argc,
const char ** const argv) {

xmlrpc_server_abyss_parms serverparm;
xmlrpc_registry * registryP;
xmlrpc_env env;

if (argc-1 != 1) {
fprintf(stderr, "You must specify 1 argument: The Abyss "
"configuration file name. You specified %d.\n", argc-1);
exit(1);
}

xmlrpc_env_init(&env);

registryP = xmlrpc_registry_new(&env);

xmlrpc_registry_add_method(
&env, registryP, NULL, "sample.add", &sample_add, NULL);

serverparm.config_file_name = argv[1];
serverparm.registryP = registryP;

printf("Starting XML-RPC server...\n");

xmlrpc_server_abyss(&env, &serverparm, XMLRPC_APSIZE(registryP));

return 0;
}


There's a lot going on under the covers of this example server. What the xmlrpc_server_abyss() statement does is run a whole HTTP server. The function doesn't normally return. The HTTP server runs the abyss web server (i.e. HTTP server) program. abyss is like the more serious web server program apache, but on a much smaller scale. An XML-RPC call is just an HTTP POST request, so while abyss was not designed specifically for XML-RPC, it provides much of the function an XML-RPC server needs.

The only way this Abyss web server differs from one you would run to do traditional web serving is that it contains a special handler to call Xmlrpc-c functions to handle an XML-RPC POST request. The server calls that handler for any URI that starts with "/RPC2", which is what XML-RPC URIs conventionally have.

While abyss is distributed independently of Xmlrpc-c, Xmlrpc-c contains an old copy of it, somewhat modified. So you don't need to install abyss separately.

In this example, you have to provide an example abyss configuration file as a program argument. The main thing you need that file for is to specify on which TCP port the server will listen. A single "Port 8080" statement is probably enough. (I say 8080, because in the example client code above, I hardcoded 8080 as the port in the URI the client uses).

There are lots of other ways to use Xmlrpc-c libraries to build XML-RPC clients and servers. The more code you're willing to write, and the more involved in the guts of the protocol you want to get, the more control you can have.

CGI Server Example

/* A simple CGI-based XML-RPC server written in C. */

#include
#include

static xmlrpc_value *
sample_add(xmlrpc_env * const env,
xmlrpc_value * const param_array,
void * const user_data) {

xmlrpc_int32 x, y, z;

/* Parse our argument array. */
xmlrpc_decompose_value(env, param_array, "(ii)", &x, &y);
if (env->fault_occurred)
return NULL;

/* Add our two numbers. */
z = x + y;

/* Return our result. */
return xmlrpc_int_new(env, z);
}



int
main(int const argc,
const char ** const argv) {

/* Process our request. */
xmlrpc_cgi_init(XMLRPC_CGI_NO_FLAGS);
xmlrpc_cgi_add_method_w_doc("sample.add", &sample_add, NULL,
"i:ii", "Add two integers.");
xmlrpc_cgi_process_call();
xmlrpc_cgi_cleanup();

return 0;
}



Small C++ Client Example
Here is an example of C++ code that implements an XML-RPC client using the highest level facilities of Xmlrpc-c. This client sends a request to add 5 and 7 together to an XMLRPC-C server that is designed to provide the service of adding numbers.

The example server above would be a suitable server for this client.


#include
#include
#include
#include

using namespace std;

int
main(int argc, char **argv) {

if (argc-1 > 0) {
if (argv) {}
cerr << "This program has no arguments" << endl;
exit(1);
}

string const serverUrl("http://localhost:8080/RPC2");
string const methodName("sample.add");

xmlrpc_c::clientSimple myClient;
xmlrpc_c::value result;

myClient.call(serverUrl, methodName, "ii", &result, 5, 7);

int const sum((xmlrpc_c::value_int(result)));
// Assume the method returned an integer; throws error if not

cout << "Result of RPC (sum of 5 and 7): " << sum << endl;

return 0;
}


To keep it brief, we don't catch any thrown errors, though various parts of this program can throw them.

Small C++ Server Example
Here is C++ code that implements the same kind of XML-RPC server shown in C above.


#include

#include
#include
#include

using namespace std;

class sampleAddMethod : public xmlrpc_c::method {
public:
sampleAddMethod() {}

void
execute(xmlrpc_c::paramList const& paramList,
xmlrpc_c::value * const retvalP) {

int const addend(paramList.getInt(0));
int const adder(paramList.getInt(1));

paramList.verifyEnd(2);

*retvalP = xmlrpc_c::value_int(addend + adder);
}
};



int
main(int const argc,
const char ** const argv) {

xmlrpc_c::registry myRegistry;

xmlrpc_c::methodPtr const sampleAddMethodP(new sampleAddMethod);

myRegistry.addMethod("sample.add", sampleAddMethodP);

xmlrpc_c::serverAbyss myAbyssServer(
myRegistry,
8080, // TCP port on which to listen
"/tmp/xmlrpc_log" // Log file
);

myAbyssServer.run();
// xmlrpc_c::serverAbyss.run() never returns
assert(false);

return 0;
}



About This Document
This document is part of the XML-RPC For C/C++ project. It is the main user documentation for the project.

The master copy of this document lives at http://xmlrpc-c.sourceforge.net/doc/. The HTML copy there is the original source -- it is hand edited.

This is a living document. It gets updated continuously, both to document changes in Xmlrpc-c and to improve the documentation. It documents all current and past, and, where possible, future releases of Xmlrpc-c. There is no benefit to keeping an old copy of the document to use with an old copy of the code.

Bryan Henderson wrote and published the first draft of this document in November 2004, as an entirely original work. Bryan placed it in the public domain.

Artikel yang Berkaitan

0 komentar:

Post a Comment