📄 rpcgen.ms
字号:
.\".\" Must use -- tbl -- for this one.\".\" @(#)rpcgen.ms 2.2 88/08/04 4.0 RPCSRC.de BT.if \\n%=1 .tl ''- % -''...ND.\" prevent excess underlining in nroff.if n .fp 2 R.OH '\fBrpcgen\fP Programming Guide''Page %'.EH 'Page %''\fBrpcgen\fP Programming Guide'.if \\n%=1 .bp.SH\&\fBrpcgen\fP Programming Guide.NH 0\&The \fBrpcgen\fP Protocol Compiler.IX rpcgen "" \fIrpcgen\fP "" PAGE MAJOR.LP.IX RPC "" "" \fIrpcgen\fPThe details of programming applications to use Remote Procedure Calls can be overwhelming. Perhaps most daunting is the writing of the XDR routines necessary to convert procedure arguments and results into their network format and vice-versa. .LPFortunately, .I rpcgen(1) exists to help programmers write RPC applications simply and directly..I rpcgen does most of the dirty work, allowing programmers to debug the main features of their application, instead of requiring them tospend most of their time debugging their network interface code..LP.I rpcgen is a compiler. It accepts a remote program interface definition writtenin a language, called RPC Language, which is similar to C. It produces a Clanguage output which includes stub versions of the client routines, aserver skeleton, XDR filter routines for both parameters and results, and aheader file that contains common definitions. The client stubs interfacewith the RPC library and effectively hide the network from their callers.The server stub similarly hides the network from the server procedures thatare to be invoked by remote clients..I rpcgen 'soutput files can be compiled and linked in the usual way. The developerwrites server procedures\(emin any language that observes Sun callingconventions\(emand links them with the server skeleton produced by.I rpcgen to get an executable server program. To use a remote program, a programmerwrites an ordinary main program that makes local procedure calls to the client stubs produced by.I rpcgen .Linking this program with .I rpcgen 'sstubs creates an executable program. (At present the main program must be written in C)..I rpcgen options can be used to suppress stub generation and to specify the transportto be used by the server stub..LPLike all compilers, .I rpcgen reduces development timethat would otherwise be spent coding and debugging low-level routines.All compilers, including .I rpcgen ,do this at a small cost in efficiencyand flexibility. However, many compilers allow escape hatches forprogrammers to mix low-level code with high-level code. .I rpcgen is no exception. In speed-critical applications, hand-written routines can be linked with the .I rpcgen output without any difficulty. Also, one may proceed by using.I rpcgen output as a starting point, and then rewriting it as necessary.(If you need a discussion of RPC programming without.I rpcgen ,see the.I "Remote Procedure Call Programming Guide)\..NH 1\&Converting Local Procedures into Remote Procedures.IX rpcgen "local procedures" \fIrpcgen\fP.IX rpcgen "remote procedures" \fIrpcgen\fP.LPAssume an application that runs on a single machine, one which we want to convert to run over the network. Here we will demonstrate such a conversion by way of a simple example\(ema program that prints a message to the console:.ie t .DS.el .DS L.ft I/* * printmsg.c: print a message on the console */.ft CW#include <stdio.h>main(argc, argv) int argc; char *argv[];{ char *message; if (argc < 2) { fprintf(stderr, "usage: %s <message>\en", argv[0]); exit(1); } message = argv[1]; if (!printmessage(message)) { fprintf(stderr, "%s: couldn't print your message\en", argv[0]); exit(1); } printf("Message Delivered!\en"); exit(0);}.ft I/* * Print a message to the console. * Return a boolean indicating whether the message was actually printed. */.ft CWprintmessage(msg) char *msg;{ FILE *f; f = fopen("/dev/console", "w"); if (f == NULL) { return (0); } fprintf(f, "%s\en", msg); fclose(f); return(1);}.DE.LPAnd then, of course:.ie t .DS.el .DS L.ft CWexample% \fBcc printmsg.c -o printmsg\fPexample% \fBprintmsg "Hello, there."\fPMessage delivered!example%.DE.LPIf .I printmessage() was turned into a remote procedure,then it could be called from anywhere in the network. Ideally, one would just like to stick a keyword like .I remote in front of aprocedure to turn it into a remote procedure. Unfortunately,we have to live within the constraints of the C language, since it existed long before RPC did. But even without language support, it's not very difficult to make a procedure remote..LPIn general, it's necessary to figure out what the types are forall procedure inputs and outputs. In this case, we have a procedure.I printmessage() which takes a string as input, and returns an integeras output. Knowing this, we can write a protocol specification in RPClanguage that describes the remote version of .I printmessage ().Here it is:.ie t .DS.el .DS L.ft I/* * msg.x: Remote message printing protocol */.ft CWprogram MESSAGEPROG { version MESSAGEVERS { int PRINTMESSAGE(string) = 1; } = 1;} = 99;.DE.LPRemote procedures are part of remote programs, so we actually declaredan entire remote program here which contains the single procedure.I PRINTMESSAGE .This procedure was declared to be in version 1 of theremote program. No null procedure (procedure 0) is necessary because.I rpcgen generates it automatically..LPNotice that everything is declared with all capital letters. This isnot required, but is a good convention to follow..LPNotice also that the argument type is \*Qstring\*U and not \*Qchar *\*U. Thisis because a \*Qchar *\*U in C is ambiguous. Programmers usually intend itto mean a null-terminated string of characters, but it could alsorepresent a pointer to a single character or a pointer to an array ofcharacters. In RPC language, a null-terminated string is unambiguously called a \*Qstring\*U..LPThere are just two more things to write. First, there is the remoteprocedure itself. Here's the definition of a remote procedureto implement the.I PRINTMESSAGEprocedure we declared above:.ie t .DS.el .DS L.vs 11.ft I/* * msg_proc.c: implementation of the remote procedure "printmessage" */.ft CW#include <stdio.h>#include <rpc/rpc.h> /* \fIalways needed\fP */#include "msg.h" /* \fIneed this too: msg.h will be generated by rpcgen\fP */.ft I/* * Remote verson of "printmessage" */.ft CWint *printmessage_1(msg) char **msg;{ static int result; /* \fImust be static!\fP */ FILE *f; f = fopen("/dev/console", "w"); if (f == NULL) { result = 0; return (&result); } fprintf(f, "%s\en", *msg); fclose(f); result = 1; return (&result);}.vs.DE.LPNotice here that the declaration of the remote procedure.I printmessage_1() differs from that of the local procedure.I printmessage() in three ways:.IP 1.It takes a pointer to a string instead of a string itself. Thisis true of all remote procedures: they always take pointers to theirarguments rather than the arguments themselves..IP 2.It returns a pointer to an integer instead of an integer itself. This isalso generally true of remote procedures: they always return a pointerto their results..IP 3.It has an \*Q_1\*U appended to its name. In general, all remoteprocedures called by .I rpcgen are named by the following rule: the name in the program definition (here .I PRINTMESSAGE )is converted to alllower-case letters, an underbar (\*Q_\*U) is appended to it, andfinally the version number (here 1) is appended..LPThe last thing to do is declare the main client program that will callthe remote procedure. Here it is:.ie t .DS.el .DS L.ft I/* * rprintmsg.c: remote version of "printmsg.c" */.ft CW#include <stdio.h>#include <rpc/rpc.h> /* \fIalways needed\fP */#include "msg.h" /* \fIneed this too: msg.h will be generated by rpcgen\fP */main(argc, argv) int argc; char *argv[];{ CLIENT *cl; int *result; char *server; char *message; if (argc < 3) { fprintf(stderr, "usage: %s host message\en", argv[0]); exit(1); }.ft I /* * Save values of command line arguments */.ft CW server = argv[1]; message = argv[2];.ft I /* * Create client "handle" used for calling \fIMESSAGEPROG\fP on the * server designated on the command line. We tell the RPC package * to use the "tcp" protocol when contacting the server. */.ft CW cl = clnt_create(server, MESSAGEPROG, MESSAGEVERS, "tcp"); if (cl == NULL) {.ft I /* * Couldn't establish connection with server. * Print error message and die. */.ft CW clnt_pcreateerror(server); exit(1); }.ft I /* * Call the remote procedure "printmessage" on the server */.ft CW result = printmessage_1(&message, cl); if (result == NULL) {.ft I /* * An error occurred while calling the server. * Print error message and die. */.ft CW clnt_perror(cl, server); exit(1); }.ft I /* * Okay, we successfully called the remote procedure. */.ft CW if (*result == 0) {.ft I /* * Server was unable to print our message. * Print error message and die. */.ft CW fprintf(stderr, "%s: %s couldn't print your message\en", argv[0], server); exit(1); } .ft I /* * The message got printed on the server's console */.ft CW printf("Message delivered to %s!\en", server);}.DEThere are two things to note here:.IP 1..IX "client handle, used by rpcgen" "" "client handle, used by \fIrpcgen\fP"First a client \*Qhandle\*U is created using the RPC library routine.I clnt_create ().This client handle will be passed to the stub routineswhich call the remote procedure..IP 2.The remote procedure .I printmessage_1() is called exactly the same way as it is declared in .I msg_proc.c except for the inserted client handle as the first argument..LPHere's how to put all of the pieces together:.ie t .DS.el .DS L.ft CWexample% \fBrpcgen msg.x\fPexample% \fBcc rprintmsg.c msg_clnt.c -o rprintmsg\fPexample% \fBcc msg_proc.c msg_svc.c -o msg_server\fP.DETwo programs were compiled here: the client program .I rprintmsg and the server program .I msg_server .Before doing this though, .I rpcgen was used to fill in the missing pieces. .LPHere is what .I rpcgen did with the input file .I msg.x :.IP 1.It created a header file called .I msg.h that contained.I #define 'sfor.I MESSAGEPROG ,.I MESSAGEVERS and .I PRINTMESSAGE for use in the other modules..IP 2.It created client \*Qstub\*U routines in the.I msg_clnt.c file. In this case there is only one, the .I printmessage_1() that was referred to from the.I printmsg client program. The name of the output file forclient stub routines is always formed in this way: if the name of theinput file is .I FOO.x ,the client stubs output file is called.I FOO_clnt.c ..IP 3.It created the server program which calls .I printmessage_1() in.I msg_proc.c .This server program is named .I msg_svc.c .The rule for naming the server output file is similar to the previous one: for an input file called .I FOO.x ,the output server file is named
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -