The
RPC Programming Interface |
Originally published July, 1996 |
by
Carlo Kopp |
¿ 1996, 2005 Carlo Kopp |
In September 1995 issue of OSR we discussed NFS and the ONC RPC protocol, with an emphasis on NFS. In this issue we return to take a closer look at the RPC model and its programming interface. Introduction The Open Network Computing Remote Procedure Call protocol, or ONC RPC, has proven to be the most durable of the early generation of distributed computing products. Indeed, enmeshed with the NFS protocol it is part of a standard Unix system's potent arsenal of networking tools. Whilst Sun no doubt had grander objectives for RPC than it becoming a lower layer of a mainstream file serving protocol, the realities of a fragmented marketplace, and a technologically timid customer base conspired such that RPC never attained the ubiquity which Sun had no doubt intended for it. Nevertheless, the availability of the RPC programming interface to the programmer provides those prepared to play with it, a quite potent interface. Where the programmer does not need the C++ oriented object instantiation and destruction facilities of products like CORBA, RPC may well prove to be perfectly adequate. Functionally RPC protocols are built around the idea of out-of-process procedure calls. The distinction between in-process and out-of-process procedure calling is that in the former the thread of execution is wholly contained within the process in question, in the latter at some point the thread blocks while a procedure call is executed by another party, for instance a process on a remote host, or the local host (Fig.1). What an RPC protocol provides is a mechanism whereby a process can execute procedure calls both locally, and in other processes, termed servers. The initiating (calling) process is by convention termed a client process. The plumbing of the ONC RPC protocol was discussed in some detail in the September, 1995, issue. For the purpose of completeness, it is necessary to state that the RPC protocol must operate in conjunction with a lower level transport protocol (usually User Datagram Protocol or UDP) and a data presentation protocol, in this instance the eXternal Data Representation (XDR) protocol. The XDR protocol is required to ensure that big-endian hosts can talk to little-endianhosts and vice versa. Other aspects of the protocol, such as call specific parameters, are essential to allowing the client to receive appropriate replies from the server (Fig.2). The programmer seeking to develop an RPC application today has a much richer set of alternatives than a decade ago. The OSF/DCE RPC is increasingly popular, and offers facilities such as transport independence (the ability to run over protocols other than UDP/IP), Threads integration and a more sophisticated programming interface than the original ONC product. The DCE suite is an evolved derivative of the earlier Apollo (HP) NCS product. Other than these mainstream tools offered by major vendors, a quick browse on the Net will also uncover quite a few proprietary and public domain RPC products, each of which offer one or another "special" feature. To illustrate the programming model the "classic" ONC RPC is
more than adequate, indeed the absence of features "noise" makes it in
many respects better suited for a tutorial.
The Programming Interface Ideally the programming interface to an RPC scheme should be transparent to the programmer, who should be able to call remote procedures as easily as calling local procedures. In practice, however, this is seldom the case. From a technical perspective, the typical resolution to the dilemma of being able to hide the plumbing, vs the alternative of a programmer becoming wholly immersed in the plumbing, is that of a compromise. The complexity of the plumbing required to support an RPC scheme should not be underestimated. The programming interface must provide the following facilities:
A programmer wishing to use an RPC scheme would therefore typically require the insight of an experienced systems programmer should he/she wish to program the low level interfaces. Sun's resolution to this problem was a very clever idea at the time, and one which has been emulated since by other protocols. This scheme is that of an interface definition language (the current buzzword) and an associated compiler. This scheme provides a mechanism whereby the RPC interface layer can be inserted between the programming interface and the body of the procedure, in a fashion which is relatively transparent to the programmer. With ONC RPC the compiler is known as rpcgen. A programmer wishing to produce a remote procedure, or convert a local procedure to be used as a remote procedure, must first produce an interface definition in the interface language, which is termed RPC Language with ONC RPC. Compiling the interface definition with rpcgen produces the stubs required for the client and server to access the RPC library routines, a skeleton routine for the server end of the RPC program, and XDR conversion routines used to map arguments and return values. Figure 3. illustrates how this fits together. The client program will be linked with the client side RPC stubs and the RPC library, and the server side skeleton, once fleshed out with the "meat" in the procedure, is compiled and linked with the server side stubs and RPC library code. The stubs provide a mechanism which hides most of the RPC interface, in either direction, from the programmer. Whilst those experienced with RPC will probably chuckle at this simplification, it is essential to illustrating the fundamental model used. Figure 4 shows the necessary steps in the production of an RPC client server pair. The RPC and XDR Languages The RPC Language (RPCL) is the primary tool which must be mastered by the aspiring RPC programmer. A superset of the XDR definition language, RPCL has been described as a C-like language, but it does have some important differences. A good starting point is to look at the data types supported. Due the nature of the beast, some of these differ from their established C-language counterparts.
The observant reader will have noticed that unlike C, these declarations typically include a sizing component or a bound on size. This is a side effect of having to transmit data in fixed sizes per call. Types such as strings which may have variable sizes in a local procedure must have a fixed size in an RPC environment as appropriate storage must be committed. The option of dynamically adjusting to type size during execution is not a practical proposition. The type declarations described are the core of the XDR language specification. To create the RPCL, we must add the declarations for a program, a version and procedure. These are declared as: program identifier { version ver-identifier } type-specifier identifier (type-specifier) = constant; } = constant ; } = constant ; An example being: program BLOGGS { version BLGSVRS { boolean TESTBLOGGS ( input ) = 1; } = 1; } = 0x20000001; This is all it takes to define the syntax for the RPC programming interface (the SMI spec was used as the primary reference). The XDR model is supported by useful library of primitives, which allow filtering of variables between their respective C language and XDR types. Most are implemented as macros. Running the rpcgen compiler on the program declaration results in the production of C language source files, as previously noted, which define the stubs to be used at the server and the client ends, and the skeleton function for the server. The real power of this model, adopted in concept for the C++ oriented CORBA, is that it greatly simplifies the mechanics of producing clean and bug free hooks into the RPC/XDR plumbing. While this may not be an issue with small programs, larger and more complex designs can fall foul of even small errors in the interfaces. In the next issue we will look at OMG CORBA and how it extends this paradigm. |
$Revision: 1.1 $ |
Last Updated: Sun Apr 24 11:22:45 GMT 2005 |
Artwork and text ¿ 2005 Carlo Kopp |