Throwing Shapes

Throwing Shapes

by Vladi Belperchinov-Shabanski
February 03, 2005

Sometimes data processing is better when separated into different processes that may run on the same machine or even on different ones. This is the well-known client-server technique. You can do it using a known protocol (such as http) or by developing your own, specific protocol. This approach needs implementation for constructor and parser procedures for each packet type (request and response). It's possible for different packets to have the same structure so the constructor and parser will be always the same. Perhaps the simplest solution is to have key/value pairs packed with newline characters or with other separators inside a text block. Binary form with length encoding is another solution.

In an attempt to simplify this client-server interaction, the Remote Procedure Call (RPC) technique appeared. It tries to map functions inside the client code to their counterparts inside the server. RPC hides all the details between a client function call and the server function's response. This includes argument serialization (to make data appropriate to transfer over the net, also known as marshaling), transport, the server function call, and returning response data back to the client (also serialized). In some implementations, RPC also tries to remove requirements for the client and the server to run on the same operating system or hardware, or to be written in the same programming language.

In the Perl world there are several modules that offer different kinds of RPC, including RPC::Simple, RPC::XML, DCE::RPC, and more.

In this article I'll explain how to use Perl-specific features to develop a compact RPC implementation that I will name Perl-centric Remote Call (PerlRC). As the name suggests, it will run only with Perl clients and servers.

Shape

PerlRC needs to simulate a function call environment that seems familiar to the client. This requires handling the four key properties of a function call:

  • Function name
  • Function arguments
  • Calling context
  • Return data

The design of the Perl language allows generic argument handling, which means that it is possible to handle arguments without knowing them before the function call. There are also ways to discover the calling context. Finally, the caller can handle results in the same way as the called function's arguments -- generically, without knowing their details until the function call returns.

With this in mind, the PerlRC code must follow these steps:

  • Creating Transport Containers

    Essentially these are the request and response packets. I'll use hashes for both. Each one will be serialized to a scalar which the code will send to the other side with a trailing newline terminator.

    A request container resembles:

    # request hash
    
      $req1 = {
    
                'ARGS' => [          # arguments list
    
                            2,
    
                            8
    
                          ],
    
                'NAME' => 'power',   # remote function name
    
                'WANTARRAY' => 0     # calling context
    
              };
    
    
    
      # result hash for scalar context
    
      $res1 = {
    
                'RET_SCALAR' => 256  # result scalar
    
              };
    
    
    
      # result hash for array context
    
      $res2 = {
    
                'RET_ARRAY' => [     # result array
    
                                 12,
    
                                 13,
    
                                 14,
    
                                 15,
    
                                 16,
    
                                 17,
    
                                 18,
    
                               ]
    
              };
    
    
    
      # result hash for error
    
      $res3 = {
    
                # error description
    
                'ERROR' => 'No such function: test'
    
              };
  • Arguments

    To keep things simple, the first argument will represent the remote function name to call. This server must remove this argument from the list before passing on the rest to the remote function. The request container holds the name for the remote function and a separate reference to the argument list.

  • Calling Context Discovery

    Find the calling context with the built-in wantarray function and put this value (0 for scalar and 1 for array context) in the request hash.

  • Transfer Both to the Server

    Serialize the request to scalar and escape newline chars with \n. Append the newline terminator and send it to the server.

  • Unpack Request Data

    The server takes the request scalar, removes the trailing newline terminator, and unpacks the request data into a local hash that contains the function name, the calling context, and the argument list.

  • Server-side Function Call

    Find and call the required function in appropriate context. Take the result data or the error. Create a result container with separate fields for scalar and array contexts and one field for any error.

  • Pack Result Data

    Serialize the result hash, escape newlines, append a terminating newline, and send the result data to the client.

  • Client Unpack of the Result Data

    When the client receives the result container, remove the trailing newline char. Unescape any newline chars and unpack the data into a local result hash. Depending on the calling context, return to the caller either the scalar or array field from the result hash or die with an error description if such exists.

The implementation uses two modules:

  • Storable handles the serialization of arbitrary data. Serializing data converts it to a string of characters suitable for saving or sending across the network and unserializable later into the form of the original. The rest of the article will also refer to this process as packing and unpacking the data.
  • IO::Socket::INET handles the creation of Internet domain sockets.

Both modules are standard in the latest Perl distribution packages.

It is possible to use any serialization module including FreezeThaw, XML::Dumper, or even Data::Dumper + eval() instead of Storable.

[1] [2] [3] Next

Close    To Top
  • Prev Article-Programming:
  • Next Article-Programming:
  • Now: Tutorial for Web and Software Design > Programming > Perl > Programming Content
    Photoshop Tutorial
     

    Special Effect

      3D Effect
      Photoshop Articles
    Programming Tutorial
     

    C/C++ Tutorial

      Visual Basic
      C# Tutorial
    Database Tutorial
     

    MySQL Tutorial

      MS SQL Tutorial
      Oracle Tutorial
    Geek Tutorial
     

    Blogging Tutorial

      RSS Tutorial
      Podcasting Tutorial
    Graphic Design Tutorial
      Coreldraw Tutorial
      Illustrator Tutorial
      3D Tutorials
    Webmaster Articles
     

    Domain Service

      Web Hosting
      Site Promotion
    Java Tutorial/ Articles
     

    Java Servlets

      JavaEE Tutorial
     

    JavaBeans Tutorial

    XML Tutorial/ Articles
     

    XML Style

      AJAX Tutorial
      XML Mobile
    Flash Tutorial/ Articles
     

    Flash Video

      Action Script
      Flash Articles
    OS Tutorial/ Articles
      Linux Tutorial
      Symbian Tutorial
      MacOS Tutorial
    Personal Tech
      Hardware Tutorial
      Software Tutorial
      Online Auction