Difference between revisions of "Remote Procedure Calls"

From CSE330 Wiki
Jump to navigationJump to search
m
 
(14 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 +
=RPC=
 +
Remote Procedure Calls (RPC) is a general computing paradigm for invoking procedures on one computer from another.  There are many forms of RPC technology, and we will focus on XML-RPC.
 +
 
=XML-RPC=
 
=XML-RPC=
XML-RPC is a spec and a set of implementations that allow software running on disparate operating systems, running in different environments to make procedure calls over the Internet.
+
XML-RPC is an RPC protocol that uses XML encoding of RPC requests and responses over HTTP.
  
 
==Calling Remote Procedures ==
 
==Calling Remote Procedures ==
  
In XML-RPC, the programs exchange information through XML. The calling procedure request a function on a remote host using XML. A typical XML remote call will be similar to the following:
+
The calling procedure requests invokation of a function on a remote host using XML. A typical XML call looks something like this:
  
 
<code>
 
<code>
Line 17: Line 20:
 
   &lt;/params>
 
   &lt;/params>
 
&lt;/methodCall>
 
&lt;/methodCall>
 
 
 
</pre>
 
</pre>
 
</code>
 
</code>
  
Then the remote function returns its response in XML
+
The server invokes the function with the specified parameters then returns a response like this:
  
 
<code>
 
<code>
Line 34: Line 35:
 
   &lt;/params>
 
   &lt;/params>
 
&lt;/methodResponse>
 
&lt;/methodResponse>
 
 
</pre>
 
</pre>
 
</code>
 
</code>
==Data Types ==
 
  
XML-RPC is very powerful and can transmit any data. The data types are specified with
+
==Data Types==
    &lt;DATATYPE>VALUE&lt;/DATATYPE>  
+
 
The types include ''boolean'', ''dateTime'',''double'',''integer'',''string''. The binary data has to be encoded at the sender origin in BASE-64 and decoded at the end by the receiver.  The encoded binary data is send in ''base64'' tag.  It also provides ''array''s and a method to define ''struct''.
+
XML-RPC is generalized enough to transmit most any kind of data. The data types are specified like
 +
 
 +
  &lt;DATATYPE>VALUE&lt;/DATATYPE>  
 +
 
 +
The types include ''boolean'', ''dateTime'',''double'',''int'',''string''. Binary data has to be encoded at the sender in BASE-64 and decoded at the end by the receiver.  The encoded binary data is sent in a ''base64'' tag.  It also provides ''arrays'' and ''structs''.
  
 
==XML-RPC Implementations ==
 
==XML-RPC Implementations ==
In order to use XML-RPC, you need to have an XML-RPC library installed in your platform. There are several available libraries depending on your platform. You can find the list at http://www.xmlrpc.com/directory/1568/implementations
+
In order to use XML-RPC, you need to have an XML-RPC library installed for your platform and language. There are several available libraries, depending on your needs.
  
A typical RPC system could be a PHP page calling a remote procedure  to do some specific task in a server. The  passed parameters are usually based on browser's actions.
 
  
 
===XML-RPC for PHP(PHPXMLRPC)===
 
===XML-RPC for PHP(PHPXMLRPC)===
 
PHPXMLRPC is one of the several XML-RPC libraries for PHP. It is accessible at http://phpxmlrpc.sourceforge.net/
 
PHPXMLRPC is one of the several XML-RPC libraries for PHP. It is accessible at http://phpxmlrpc.sourceforge.net/
  
In order to use this library, all you need to do is to add the  include files xmlrpc.inc (to have a PHP client),  xmlrpcs.inc (to implement an RPC server). It also provides several helper and wrapper functions that require other include files. You can look at the documentation to learn more about them. For this module, we will concentrate on client functions.
+
In order to use this library, you need to download and unzip the package.  A handful of .inc files are included in the distribution for PHP clients and servers.  Include them in your PHP scripts to get access to the functionality in the library. For example, xmlrpc.inc is the client library and xmlrpcs.inc is the server library. It also provides several helper and wrapper functions that require other include files. You can look at the documentation to learn more about them. For this module, we will concentrate on client functionality.
  
 
==== Creating a client in PHP ====
 
==== Creating a client in PHP ====
''xmlrpc_client'' provides a client object. You can create a new client using
+
''xmlrpc_client'' is the XML-RPC client class. You can create a new client using
$client=new xmlrpc_client ( server_url )
+
 
 +
$client = new xmlrpc_client( server_url )
 +
 
 +
It also supports basic HTTP authentication
  
It also provides the basic HTTP authentication
+
$client=(  http(s)://user:password@server_url:port/path)
  $client=(  http(s)://user:password@server_url:port/path)
 
  
  For example, the following code creates a connection to the demo server
+
For example, the following code creates a connection to the PHPXMLRPC demo server
  
 
<code>
 
<code>
Line 70: Line 74:
 
</pre>
 
</pre>
 
</code>
 
</code>
 +
 
====PHPXMLRPC variables ====
 
====PHPXMLRPC variables ====
The parameters (to or from remote procedures) are specified using ''xmlrpcval'' function. This function could be called in several format:
+
The parameters(to or from remote procedures) are specified using the ''xmlrpcval'' function. This function can be called in different ways:
  
 
  new xmlrpcval ( )
 
  new xmlrpcval ( )
  new xmlrpcval ( string )
+
  new xmlrpcval ( string )
 
  new xmlrpcval ( VALUE, TYPE )
 
  new xmlrpcval ( VALUE, TYPE )
 
  new xmlrpcval ( ARRAY, ARRAY_TYPE )
 
  new xmlrpcval ( ARRAY, ARRAY_TYPE )
  
If ''xmlrpcval'' is called without a parameter, you need to set the variables by calling addScalar, addArray or addStruct functions to initialize the variable. If ''xmlrpcval'' is called with a string, the variable is assumed to be of type ''string'', and the value is specified in the string parameter. A third option is to pass the value and type of a variable.  The fourth option is to create complex variables of arrays and structures.
+
If ''xmlrpcval'' is called without a parameter, you need to set the variables by calling the ''addScalar'', ''addArray'' or ''addStruct'' functions to initialize the variable. If ''xmlrpcval'' is called with a string, the variable is assumed to be of type string, and the value is specified in the string parameter. A third option is to pass the value and type of a variable.  The fourth option is to create complex variables of arrays and structures.
  $myInt = new xmlrpcvalue(1267, "int");
+
 
  $myString = new xmlrpcvalue("Hello, World!", "string");
+
  $myInt = new xmlrpcval(1267, "int");
  $myBool = new xmlrpcvalue(1, "boolean");
+
  $myString = new xmlrpcval("Hello, World!", "string");
 +
  $myBool = new xmlrpcval(1, "boolean");
 
  // note: this will serialize a php float value as xml-rpc string
 
  // note: this will serialize a php float value as xml-rpc string
  $myString2 = new xmlrpcvalue(1.24, "string");
+
  $myString2 = new xmlrpcval(1.24, "string");
 
  $myArray = new xmlrpcval(
 
  $myArray = new xmlrpcval(
 
   array(
 
   array(
Line 104: Line 110:
 
   ),  
 
   ),  
 
   "struct");
 
   "struct");
 
  
 
Once you have your variables ready, you can send them to the remote server.
 
Once you have your variables ready, you can send them to the remote server.
Line 110: Line 115:
 
==== Preparing a message ====
 
==== Preparing a message ====
  
In order to make an RPC, first you need to prepare a message. This is done through ''xmlrpcmsg'' class.
+
In order to make an RPC, first you need to prepare a message. This is done through the ''xmlrpcmsg'' class.
  
 
  $message = new xmlrpcmsg("REMOTE_FUNCTION", PARAMETER_ARRAY);
 
  $message = new xmlrpcmsg("REMOTE_FUNCTION", PARAMETER_ARRAY);
  
Remote function is the name of the function on the remote machine. Parameter array stores the parameters. It can be skipped, if the function is not taking any parameters.
+
Remote function is the name of the function on the remote machine. Parameter array stores the parameters formed above. It can be skipped if the function does not take any parameters.
 +
 
 +
For example, the following PHP code sends a message to the demo server to call an existing function:
  
For example, the following PHP code sends a message  the demo server  to call an existing function:
 
 
  $myParams=array(new xmlrpcval(23, "int"));
 
  $myParams=array(new xmlrpcval(23, "int"));
 
  $msg = new xmlrpcmsg("examples.getStateName", $myParams);
 
  $msg = new xmlrpcmsg("examples.getStateName", $myParams);
  
==== Calling the function and receiving response ====
+
==== Calling the function and receiving a response ====
 
The actual RPC is done when the client's ''send'' function is called.
 
The actual RPC is done when the client's ''send'' function is called.
  
 
  $client->return_type = 'phpvals';
 
  $client->return_type = 'phpvals';
 
  $resp = $client->send($msg);
 
  $resp = $client->send($msg);
  if ($resp->faultCode())
+
  if($resp->faultCode())
   echo ' Error: '.$resp->faultString();
+
   echo 'Error: ' . $resp->faultString();
 
  else
 
  else
   echo 'OK: got '.$resp->value();
+
   echo 'OK: got ' . $resp->value();
  
client's return_type specify either we want to get the response in XML or as php variable.
+
The client's return_type specifies either that the result should be stored in XML or as PHP variables. If there was an error during the call, the response's error code will be set. Otherwise, the value function returns the response value.
If there was an error during the call, the response's fault code will be set. Otherwise, the value function returns the response value.
 
  
===Perl Frontier  Module ===
+
===Python Server and PHP Client ===
Perl has two modules for XML-RPC. XML::RPC provides a very basic XML-RPC functionality for both client and server side. An alternative is Frontier::* modules. For this module, we will concentrate on Frontier::Daemon which provides ''server'' functions.
+
Python and PHP both have several different libraries available to implement XML-RPC. First we will look at setting up a very simple Python XML-RPC server that returns the larger of two ints. We will do this using the SimpleXMLRPCServer library.
 +
 
 +
<code>
 +
<pre>
 +
from SimpleXMLRPCServer import SimpleXMLRPCServer
  
  
You can initialize the daemon by calling  new function. The arguments include the port address and function names to serve. For example
+
def largerNumber(x, y):
 +
    if x>y:
 +
        return x
 +
    else:
 +
        return y
 +
 
 +
server = SimpleXMLRPCServer(("127.0.0.1", 8000))
 +
print "Listening on port 8000..."
 +
server.register_multicall_functions()
 +
server.register_function(largerNumber, 'largerNumber')
 +
server.serve_forever()
 +
</pre>
 +
</code>
 +
The Python server defines an RPC method called largerNumber which takes two inputs and returns the larger of the two. Next we create our XML-RPC server instructing it to bind (or listen) to the IP address 127.0.0.1.  This is a special IP address called the loopback address or the localhost. This forces the server to only accept request sent to the ec2 instance from that instance itself.  Typically your client and server would have unique IP addresses and the XML-RPC message would travel over the Internet.
 +
 
 +
For the PHP client, all we need to do is setup a new XML-RPC connection to the server. In this case the server is the same ec2 instance as the client so we use the loopback IP address. Next we pass in two ints for the RPC server to compare, $first and $second.  We then create a XML RPC message with the function we wish to call and an array containing the arguments for the function.  Finally, we send the message, get the response, convert it to a scalar value, and display it.
 +
 
 +
<code>
 +
<pre>
 +
<?php
 +
  include("xmlrpc.inc"); //for xmlrpc operations
 +
 
 +
  $client = new xmlrpc_client("http://127.0.0.1:8000:/"); //your host
 +
 
 +
$first=1;
 +
$second=2;
 +
 +
$msg = new xmlrpcmsg('largerNumber',
 +
                        array(new xmlrpcval($first, 'int'),
 +
                        new xmlrpcval($second, 'int')));
 +
 
 +
$resp = $client->send($msg);
 +
 
 +
$struct = $resp->value();
 +
$largerNumber = $struct->scalarval();
 +
print $largerNumber . "\n"; 
 +
 
 +
?>
 +
</pre>
 +
</code>
 +
 
 +
===Perl Frontier  Module and PHP client ===
 +
Perl has a few different modules for XML-RPC.  We will use the Frontier::* modules, focusing on Frontier::Daemon which provides XML-RPC server functionality.
 +
 
 +
You can initialize the daemon with the ''new'' function. The arguments include the port number to listen on and function names to serve to clients. For example:
  
 
<code>
 
<code>
Line 143: Line 196:
 
use Frontier::Daemon;
 
use Frontier::Daemon;
  
$methods = {'myservice.convert' => \&convert
+
$methods = { 'myservice.convert' => \&convert };
    };
 
 
 
Frontier::Daemon->new(LocalPort => 4873,  methods => $methods)
 
        or die "Couldn't start HTTP server: $!";
 
  
 +
Frontier::Daemon->new(LocalPort => 4873,  methods => $methods) or die "Couldn't start HTTP server: $!";
 
</pre>
 
</pre>
 
</code>
 
</code>
Will set up the daemon at port 4873 and the function ''convert'' is called from the remote clients as ''myservice.convert''.
+
 
In the following example, the daemon receives a Base64 encoded image, decodes,save,modify it and sends the modified image back in Base64. Please note that it assumes just single user is using the system at any time, if multiple users access, the files could be overwritten.
+
This will set up the daemon at port 4873 and the function ''convert'' is called from the remote clients as ''myservice.convert''.
 +
In the following example, the daemon receives a Base64 encoded image, decodes, saves, and modifies it, and then sends the modified image back in Base64. Note that it assumes just single user is using the system at any time.  If multiple users access the same server the files could be overwritten.
  
 
<code>
 
<code>
Line 163: Line 214:
 
$|=1;
 
$|=1;
 
print "server $$";
 
print "server $$";
$methods = {'myservice.convert' => \&convert
+
$methods = { 'myservice.convert' => \&convert };
    };
 
  
 
#initialize daemon
 
#initialize daemon
Frontier::Daemon->new(LocalPort => 4873,  methods => $methods,ReuseAddr=>1)
+
Frontier::Daemon->new(LocalPort => 4873,  methods => $methods, ReuseAddr=>1) or die "Couldn't start HTTP server: $!";
        or die "Couldn't start HTTP server: $!";
 
  
sub convert{
+
sub convert
  ($name,$encoded)=@_; #client sends filename and file in base64
+
{
  print "Name:$name\n\n\n\n";
+
  ($name,$encoded) = @_; #client sends filename and file in base64
  $decoded = MIME::Base64::decode($encoded);
+
  print "Name:$name\n\n\n\n";
  open(OUT,">/tmp/$name"); #save the image
+
  $decoded = MIME::Base64::decode($encoded);
    print OUT $decoded;
+
  open(OUT,">/tmp/$name"); #save the image
  close(OUT);
+
  print OUT $decoded;
    #put a label over the image
+
  close(OUT);
    system("convert -pointsize 40 -draw \"text 200,200 'cse330'\" /tmp/$name /tmp/a2.jpg");
+
 
  #read back the image
+
  #put a label over the image
  open(IN,"</tmp/a2.jpg");
+
  system("convert -pointsize 40 -draw \"text 200,200 'cse330'\" /tmp/$name /tmp/a2.jpg");
  binmode(IN);
+
 
  read IN,$de,1000000;
+
  #read back the image
  close(OUT);
+
  open(IN,"</tmp/a2.jpg");
 +
  binmode(IN);
 +
  read IN,$de,1000000;
 +
  close(OUT);
 
      
 
      
  #encode it
+
  #encode it
  $encoded = MIME::Base64::encode($de);
+
  $encoded = MIME::Base64::encode($de);
  #print $encoded;
+
  #print $encoded;
  #send it back
+
 
  return {'success' => "true",'result' =>$encoded};
+
  #send it back
 
+
  return {'success' => "true",'result' => $encoded};
 
 
 
 
 
}
 
}
 
</pre>
 
</pre>
Line 202: Line 252:
 
&lt;html>
 
&lt;html>
 
&lt;body>
 
&lt;body>
&lt;form enctype="multipart/form-data" action="image-xmlrpc.php" method="POST">
+
  &lt;form enctype="multipart/form-data" action="image-xmlrpc.php" method="POST">
&lt;input type="hidden" name="MAX_FILE_SIZE" value="100000" />
+
  &lt;input type="hidden" name="MAX_FILE_SIZE" value="100000" />
Choose an image  file to upload: &lt;input name="uploadedfile" type="file" />&lt;br />
+
  Choose an image  file to upload: &lt;input name="uploadedfile" type="file" />&lt;br />
&lt;input type="submit" value="Upload File" />
+
  &lt;input type="submit" value="Upload File" />
&lt;/form>
+
  &lt;/form>
</body>
+
&lt/body>
 
&lt;/html>
 
&lt;/html>
 
 
 
</pre>
 
</pre>
 
</code>
 
</code>
  
 
+
Finally, a PHP based client that would send the uploaded image to the RPC server, and display the modified image.
Finally a php based client that would send the uploaded image to RPC server, and display the modified image.
 
 
<code>
 
<code>
 
<pre>
 
<pre>
&lt;?
+
&lt;?php
 +
  $uploadfile = $_FILES['uploadedfile']['tmp_name'];
 +
  $handle = fopen($uploadfile,'r');
 +
  $file_content = fread($handle,filesize($uploadfile)); //read uploaded file
 +
  fclose($handle);
 +
  $encoded = chunk_split(base64_encode($file_content)); //encode it
 +
  include("xmlrpc.inc"); //for xmlrpc operations
  
$uploadfile=  $_FILES['uploadedfile']['tmp_name'];
+
  $client = new xmlrpc_client("http://127.0.0.1:4873/RPC2"); //your host
$handle = fopen($uploadfile,'r');
+
      $file_content = fread($handle,filesize($uploadfile)); //read uploaded file
+
  $myParams = array(new xmlrpcval($_FILES['uploadedfile']['name'], "string"),
      fclose($handle);
+
                    new xmlrpcval($encoded, "string"));
      $encoded = chunk_split(base64_encode($file_content)); //encode it
 
      include("xmlrpc.inc"); //for xmlrpc operations
 
 
 
$client = new xmlrpc_client("http://127.0.0.1:4873/RPC2"); //your host
 
 
   
 
   
$myParams=array(new xmlrpcval($_FILES['uploadedfile']['name'], "string"),
+
  $message = new xmlrpcmsg("myservice.convert", $myParams);
                new xmlrpcval($encoded, "string")
+
  $resp = $client->send($message);
);
+
  if ($resp->faultCode())
$message = new xmlrpcmsg("myservice.convert", $myParams);
+
   {
$resp = $client->send($message);
+
    echo 'KO. Error: '.$resp->faultString();
if ($resp->faultCode())
+
  }
   echo 'KO. Error: '.$resp->faultString();
+
  else
else{
+
  {
  $struct=$resp->value();
+
    $struct=$resp->value();
  $retvalue = $struct->structmem('success'); //value of the field success
+
    $retvalue = $struct->structmem('success'); //value of the field success
 
     $resultval = $struct->structmem('result'); //result field
 
     $resultval = $struct->structmem('result'); //result field
        $result = $resultval->scalarval(); //encoded image from the result
+
    $result = $resultval->scalarval(); //encoded image from the result
 
 
      $decoded = base64_decode($result); //decode the base64 data
 
$handle = fopen("changed.jpg",'w'); //save it to a new file
 
      $file_content = fwrite($handle,$decoded);
 
      fclose($handle);
 
 
 
      echo "<img src='changed.jpg'/><br>"; //display the new image
 
 
 
}
 
  
 +
    $decoded = base64_decode($result); //decode the base64 data
 +
    $handle = fopen("changed.jpg",'w'); //save it to a new file
 +
    $file_content = fwrite($handle,$decoded);
 +
    fclose($handle);
  
 +
    echo "<img src='changed.jpg'/><br>"; //display the new image
 +
  }
 
?&gt;
 
?&gt;
 +
</pre>
 +
</code>
  
  
 
+
[[Category:Module 4]]
</pre>
+
[[Category:Former Content]]
</code>
 

Latest revision as of 07:55, 8 April 2013

RPC

Remote Procedure Calls (RPC) is a general computing paradigm for invoking procedures on one computer from another. There are many forms of RPC technology, and we will focus on XML-RPC.

XML-RPC

XML-RPC is an RPC protocol that uses XML encoding of RPC requests and responses over HTTP.

Calling Remote Procedures

The calling procedure requests invokation of a function on a remote host using XML. A typical XML call looks something like this:

<?xml version="1.0"?>
<methodCall>
  <methodName>FunctionName</methodName>
  <params>
    <param>
        <value><DATATYPE>DATAVALUE</DATATYPE></value>
    </param>
  </params>
</methodCall>

The server invokes the function with the specified parameters then returns a response like this:

<?xml version="1.0"?>
<methodResponse>
  <params>
    <param>
        <value><DATATYPE>VALUE</DATATYPE></value>
    </param>
  </params>
</methodResponse>

Data Types

XML-RPC is generalized enough to transmit most any kind of data. The data types are specified like

 <DATATYPE>VALUE</DATATYPE> 

The types include boolean, dateTime,double,int,string. Binary data has to be encoded at the sender in BASE-64 and decoded at the end by the receiver. The encoded binary data is sent in a base64 tag. It also provides arrays and structs.

XML-RPC Implementations

In order to use XML-RPC, you need to have an XML-RPC library installed for your platform and language. There are several available libraries, depending on your needs.


XML-RPC for PHP(PHPXMLRPC)

PHPXMLRPC is one of the several XML-RPC libraries for PHP. It is accessible at http://phpxmlrpc.sourceforge.net/

In order to use this library, you need to download and unzip the package. A handful of .inc files are included in the distribution for PHP clients and servers. Include them in your PHP scripts to get access to the functionality in the library. For example, xmlrpc.inc is the client library and xmlrpcs.inc is the server library. It also provides several helper and wrapper functions that require other include files. You can look at the documentation to learn more about them. For this module, we will concentrate on client functionality.

Creating a client in PHP

xmlrpc_client is the XML-RPC client class. You can create a new client using

$client = new xmlrpc_client( server_url )

It also supports basic HTTP authentication

$client=(  http(s)://user:password@server_url:port/path)

For example, the following code creates a connection to the PHPXMLRPC demo server

<?
include("xmlrpc.inc");
$client = new xmlrpc_client("http://phpxmlrpc.sourceforge.net/server.php");
?>

PHPXMLRPC variables

The parameters(to or from remote procedures) are specified using the xmlrpcval function. This function can be called in different ways:

new xmlrpcval ( )
new xmlrpcval ( string )
new xmlrpcval ( VALUE, TYPE )
new xmlrpcval ( ARRAY, ARRAY_TYPE )

If xmlrpcval is called without a parameter, you need to set the variables by calling the addScalar, addArray or addStruct functions to initialize the variable. If xmlrpcval is called with a string, the variable is assumed to be of type string, and the value is specified in the string parameter. A third option is to pass the value and type of a variable. The fourth option is to create complex variables of arrays and structures.

$myInt = new xmlrpcval(1267, "int");
$myString = new xmlrpcval("Hello, World!", "string");
$myBool = new xmlrpcval(1, "boolean");
// note: this will serialize a php float value as xml-rpc string
$myString2 = new xmlrpcval(1.24, "string");
$myArray = new xmlrpcval(
 array(
   new xmlrpcval("Tom"),
   new xmlrpcval("Dick"),
   new xmlrpcval("Harry")
 ),
 "array");
// recursive struct
$myStruct = new xmlrpcval(
 array(
   "name" => new xmlrpcval("Tom", "string"),
   "age" => new xmlrpcval(34, "int"),
   "address" => new xmlrpcval(
     array(
       "street" => new xmlrpcval("Fifht Ave", "string"),
       "city" => new xmlrpcval("NY", "string")
     ), 
     "struct")
 ), 
 "struct");

Once you have your variables ready, you can send them to the remote server.

Preparing a message

In order to make an RPC, first you need to prepare a message. This is done through the xmlrpcmsg class.

$message = new xmlrpcmsg("REMOTE_FUNCTION", PARAMETER_ARRAY);

Remote function is the name of the function on the remote machine. Parameter array stores the parameters formed above. It can be skipped if the function does not take any parameters.

For example, the following PHP code sends a message to the demo server to call an existing function:

$myParams=array(new xmlrpcval(23, "int"));
$msg = new xmlrpcmsg("examples.getStateName", $myParams);

Calling the function and receiving a response

The actual RPC is done when the client's send function is called.

$client->return_type = 'phpvals';
$resp = $client->send($msg);
if($resp->faultCode())
  echo 'Error: ' . $resp->faultString();
else
  echo 'OK: got ' . $resp->value();

The client's return_type specifies either that the result should be stored in XML or as PHP variables. If there was an error during the call, the response's error code will be set. Otherwise, the value function returns the response value.

Python Server and PHP Client

Python and PHP both have several different libraries available to implement XML-RPC. First we will look at setting up a very simple Python XML-RPC server that returns the larger of two ints. We will do this using the SimpleXMLRPCServer library.

from SimpleXMLRPCServer import SimpleXMLRPCServer


def largerNumber(x, y):
    if x>y:
        return x
    else:
        return y

server = SimpleXMLRPCServer(("127.0.0.1", 8000))
print "Listening on port 8000..."
server.register_multicall_functions()
server.register_function(largerNumber, 'largerNumber')
server.serve_forever()

The Python server defines an RPC method called largerNumber which takes two inputs and returns the larger of the two. Next we create our XML-RPC server instructing it to bind (or listen) to the IP address 127.0.0.1. This is a special IP address called the loopback address or the localhost. This forces the server to only accept request sent to the ec2 instance from that instance itself. Typically your client and server would have unique IP addresses and the XML-RPC message would travel over the Internet.

For the PHP client, all we need to do is setup a new XML-RPC connection to the server. In this case the server is the same ec2 instance as the client so we use the loopback IP address. Next we pass in two ints for the RPC server to compare, $first and $second. We then create a XML RPC message with the function we wish to call and an array containing the arguments for the function. Finally, we send the message, get the response, convert it to a scalar value, and display it.

<?php
   include("xmlrpc.inc"); //for xmlrpc operations

  $client = new xmlrpc_client("http://127.0.0.1:8000:/"); //your host

 $first=1;
 $second=2;
 
 $msg = new xmlrpcmsg('largerNumber',
                         array(new xmlrpcval($first, 'int'),
                         new xmlrpcval($second, 'int')));

 $resp = $client->send($msg);

 $struct = $resp->value();
 $largerNumber = $struct->scalarval();
 print $largerNumber . "\n";  

?>

Perl Frontier Module and PHP client

Perl has a few different modules for XML-RPC. We will use the Frontier::* modules, focusing on Frontier::Daemon which provides XML-RPC server functionality.

You can initialize the daemon with the new function. The arguments include the port number to listen on and function names to serve to clients. For example:

use Frontier::Daemon;

$methods = { 'myservice.convert' => \&convert };

Frontier::Daemon->new(LocalPort => 4873,  methods => $methods) or die "Couldn't start HTTP server: $!";

This will set up the daemon at port 4873 and the function convert is called from the remote clients as myservice.convert. In the following example, the daemon receives a Base64 encoded image, decodes, saves, and modifies it, and then sends the modified image back in Base64. Note that it assumes just single user is using the system at any time. If multiple users access the same server the files could be overwritten.

#!/usr/bin/perl
use MIME::Base64;
use Frontier::Daemon;
use Frontier::RPC2;

$|=1;
print "server $$";
$methods = { 'myservice.convert' => \&convert };

#initialize daemon
Frontier::Daemon->new(LocalPort => 4873,  methods => $methods, ReuseAddr=>1) or die "Couldn't start HTTP server: $!";

sub convert
{
  ($name,$encoded) = @_; #client sends filename and file in base64
  print "Name:$name\n\n\n\n";
  $decoded = MIME::Base64::decode($encoded);
  open(OUT,">/tmp/$name"); #save the image
  print OUT $decoded;
  close(OUT);
  
  #put a label over the image
  system("convert -pointsize 40 -draw \"text 200,200 'cse330'\" /tmp/$name /tmp/a2.jpg");
  
  #read back the image
  open(IN,"</tmp/a2.jpg");
  binmode(IN);
  read IN,$de,1000000;
  close(OUT);
    
  #encode it
  $encoded = MIME::Base64::encode($de);
  #print $encoded;
  
  #send it back
  return {'success' => "true",'result' => $encoded};
}

On the client side, you may have an upload page:

<html>
<body>
  <form enctype="multipart/form-data" action="image-xmlrpc.php" method="POST">
  <input type="hidden" name="MAX_FILE_SIZE" value="100000" />
  Choose an image  file to upload: <input name="uploadedfile" type="file" /><br />
  <input type="submit" value="Upload File" />
  </form>
&lt/body>
</html>

Finally, a PHP based client that would send the uploaded image to the RPC server, and display the modified image.

<?php
  $uploadfile = $_FILES['uploadedfile']['tmp_name'];
  $handle = fopen($uploadfile,'r');
  $file_content = fread($handle,filesize($uploadfile)); //read uploaded file
  fclose($handle);
  $encoded = chunk_split(base64_encode($file_content)); //encode it
  include("xmlrpc.inc"); //for xmlrpc operations

  $client = new xmlrpc_client("http://127.0.0.1:4873/RPC2"); //your host
 
  $myParams = array(new xmlrpcval($_FILES['uploadedfile']['name'], "string"),
                    new xmlrpcval($encoded, "string"));
 
  $message = new xmlrpcmsg("myservice.convert", $myParams);
  $resp = $client->send($message);
  if ($resp->faultCode())
  {
    echo 'KO. Error: '.$resp->faultString();
  }
  else
  {
    $struct=$resp->value();
    $retvalue = $struct->structmem('success'); //value of the field success
    $resultval = $struct->structmem('result'); //result field
    $result = $resultval->scalarval(); //encoded image from the result

    $decoded = base64_decode($result); //decode the base64 data
    $handle = fopen("changed.jpg",'w'); //save it to a new file
    $file_content = fwrite($handle,$decoded);
    fclose($handle);

    echo "<img src='changed.jpg'/><br>"; //display the new image
  }
?>