390 likes | 521 Vues
This chapter delves into the concept of Remote Procedure Calls (RPC) using RPCgen as a program specification technique in UNIX network programming. It covers key processes such as input/output handling, RPC programming mechanisms, the structure of client-server communication, and the practical use of XDR library routines for data conversion. Additionally, it discusses server and client stub generation, registration of services with Portmap, and the inception of connections through various protocols (TCP/UDP). Included examples illustrate temperature conversion through a server-client structure.
E N D
Linux RPC Comer Chapter 21 (RPCgen Concept) RFC 1057 – RPC Spec. UNIX Network Programming - Stevens
Using Remote Procedure Calls • As a program specification technique • For program specification and as an abstraction during design • Explicitly in the implementation • For design and implementation, from scratch • For design and implementation, with standard libraries • For automated implementation
RPC Programming MechanismsONC (Open Network Computing) • XDR library routines for data conversion • XDR library routines for complex data structures • RPC run-time library routines • Program generator tool
RPC Programming Process • Dividing the program into local and remote procedures. RPC Proc A Server Stub Client Stub Proc B
RPC Dispatching(Procedure Location) RPC Proc A2 Dispatcher Proc A1 RPC Server Stub Server Stub Client Stub Client Stub Proc B1 Proc B2
RPC Interface Specification Proc A Server Comm RPC Client Iface Server Iface Client comm Proc B
RPCgen Input and Output • Input • Q.x Interface specification file • Output • Q.h Declarations header file • Q_xdr.cpp XDR procedure calls used to marshal arguments • Q_clnt.cpp Client-side communications stub • Q_svc.cpp Server-side communications stub
RPC Process Flow Client application Client interface Q_clnt.cpp compile Client Q.h rpcgen Q.x Q_xdr.cpp compile Server Q_svc.cpp Remote procedures Server interface
RPC General Build Procedure Develop Interface Develop Client Develop Server
Developing the Interface MyApp.x RPCgen MyApp_clnt.c Client Stub MyApp.h MyApp_svc.c Server Stub MyApp_xdr.c
Developing the Server MyApp.x RPCgen MySrvr.c MyApp_xdr.c MyApp.h C Compiler MyApp_svc.c Server Stub Linker MySrvr.exe
Developing the Client MyApp.idl RPCgen MyClnt.c MyApp_xdr.c MyApp.h C Compiler MyApp_clnt.c Client Stub Linker MyClnt.exe
How the Server Prepares for a Connection • (Be certain that Portmap is running) • Create UDP service • Register UDP service with Portmap • Create TCP service • Register TCP service with Portmap • Run service... • Uses select( ) to monitor ports.
Start Portmap Portmap is included in all Linux distributions as a standard server. Under Red Hat Fedora Open services applet ,select portmap and start From command line (as root) /sbin/services portmap start Other distributions should be similar
Server concurrency mode RPC servers can be created in either single threaded or multi-threaded mode. Servers automatically create and (when done) destroy a thread for each incoming connection.
Register the Server Program svc_register(port#, SERV#, VER#, serv_func, proto#); port#: port on which the service is active SERV#: unique number for the service VER#: version for this particular service serv_func: name by which this function is called proto#: IPPROTO_UDP or IPPROTO_TCP
How the Client Establishes a Connection • Make a Remote Procedure Call • Find the Server Host Computer • Find Server Process Port # (through Portmap) • Create a (connection) to the Server Process
How the Client Establishes a Connection clnt_create(server, SERV#, VER#, proto#); remote procedure call... Clnt_destroy(CLIENT);
Example #1 • Temperature Server (Fahrenheit to Centigrade) • Parameters passed as integers • TCP / IP port connection • Source files: • temp.x • Tclient.c • tempServer.c
temp.x program TEMPSERV { version TEMPVERS { intTempConv(int) = 1; //procedure number } = 1; //version number } = 77; //program number
TClient.c #include <stdio.h>, <stdlib.h>, <string.h> #include <rpc/rpc.h> #include "temp.h" #define YES 0 #define NO 1 void main (int argc, char *argv[]) { int tempconvert(int temp, char *srvr); int temperature, nuTemp; int loopFlag; char srvr[25]; CLIENT * cl;
TClient.c (cont) strcpy (srvr, argv[1]); cl = clnt_create(srvr, TEMPSERV, TEMPVERS, "tcp"); loopFlag = YES; while(loopFlag == YES) { printf("Enter temperature in Faherenheit (-999 to quit)"); scanf ("%d", &temperature); ans = tempconv_1(&temperature, cl);
TClient.c (cont) if (ans != NULL) nuTemp = * ans; if (temperature == -999 || temperature == -9999) { loopFlag = NO; printf ("Goodbye...\n"); continue; } printf("That’s %2d in centigrade\n", nuTemp); } clnt_destroy(cl); return 0; }
tempServer.c #include <stdlib.h>, <unistd.h>, <stdio.h> #include <rpc/rpc.h>, "temp.h" static int count; static int nuTemp; int *tempconv_1_svc (int *val, struct svc_req * rqst) { int oldTemp; oldTemp = *val;
tempServer.c if (oldTemp == -9999) { printf("We're shutting down...\n"); exit (0); } printf("We got a temperature of %d, ", oldTemp); count++; nuTemp = (int)((5*(oldTemp -32)) / 9.0); printf("and we returned a value of %d\n", nuTemp); sleep(1); return (&nuTemp); }
Files created with rpcgen • Input: • temp.x • Output • temp.h • temp_xdr.c (NULL file) • temp_clnt.c • temp_svc.c
temp.h #include <rpc/rpc.h> #ifdef __cplusplus extern "C" { #endif #define TEMPSERV 77 #define TEMPVERS 1 #if defined(__STDC__) || defined(__cplusplus) #define TempConv 1 extern int * tempconv_1(int *, CLIENT *); extern int * tempconv_1_svc(int *, structsvc_req *); extern int tempserv_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t); #ifdef __cplusplus} #endif #endif /* !_TEMP_H_RPCGEN */
temp_xdr.c #include <rpc/rpc.h> #include "temp.h"
temp_clnt.c #include <memory.h> /* for memset */ #include "temp.h“ /* Default timeout can be changed using clnt_control() */ static structtimeval TIMEOUT = { 25, 0 }; int *tempconv_1(int *argp, CLIENT *clnt){ static intclnt_res; memset((char *)&clnt_res, 0, sizeof(clnt_res));
temp_clnt.c (cont) if (clnt_call (clnt, TempConv, (xdrproc_t) xdr_int, (caddr_t) argp, (xdrproc_t) xdr_int, (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res);}
temp_svc.c #include "temp.h“ #include <stdio.h> #include <stdlib.h> #include <rpc/pmap_clnt.h> #include <string.h> #include <memory.h> #include <sys/socket.h> #include <netinet/in.h> #ifndef SIG_PF #define SIG_PF void(*)(int) #endif
temp_svc.c (cont) static void tempserv_1(structsvc_req *rqstp, register SVCXPRT *transp){ union { int tempconv_1_arg; } argument; char *result; xdrproc_t _xdr_argument, _xdr_result; char *(*local)(char *, structsvc_req *); switch (rqstp->rq_proc) { case NULLPROC: (void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL); return; case TempConv: _xdr_argument = (xdrproc_t) xdr_int; _xdr_result = (xdrproc_t) xdr_int; local = (char *(*)(char *, structsvc_req *)) tempconv_1_svc; break; default: svcerr_noproc (transp); return; }
temp_svc.c (cont) memset ((char *)&argument, 0, sizeof (argument)); if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { svcerr_decode (transp); return; } result = (*local)((char *)&argument, rqstp); if (result != NULL && !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) { svcerr_systemerr (transp); } if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { fprintf (stderr, "%s", "unable to free arguments"); exit (1); } return; }
temp_svc.c (cont) int main (intargc, char **argv){ register SVCXPRT *transp; pmap_unset (TEMPSERV, TEMPVERS); transp = svcudp_create(RPC_ANYSOCK); if (transp == NULL) { fprintf (stderr, "%s", "can’t create udp service."); exit(1); } if (!svc_register(transp, TEMPSERV, TEMPVERS, tempserv_1, IPPROTO_UDP)) { fprintf (stderr, "%s", "unable to register (TEMPSERV, TEMPVERS, udp)."); exit(1); }
temp_svc.c (cont) transp = svctcp_create(RPC_ANYSOCK, 0, 0); if (transp == NULL) { fprintf (stderr, "%s", "cannot create tcp service."); exit(1); } if (!svc_register(transp, TEMPSERV, TEMPVERS, tempserv_1, IPPROTO_TCP)) { fprintf (stderr, "%s", "unable to register (TEMPSERV, TEMPVERS, tcp)."); exit(1); } svc_run (); fprintf (stderr, "%s", "svc_run returned"); exit (1); /* NOTREACHED */}
Sample Client Output D:\data\RPC\onrpc_temp\client\Debug>client localhost Enter the temperature in Faherenheit (-999 to quit)32 That would be 0 in centigrade Enter the temperature in Faherenheit (-999 to quit)100 That would be 37 in centigrade Enter the temperature in Faherenheit (-999 to quit)212 That would be 100 in centigrade Enter the temperature in Faherenheit (-999 to quit)-9999 Goodbye... D:\data\RPC\onrpc_temp\client\Debug>
Sample Server Output D:\data\RPC\examples\onrpc_temp\server\Debug>server We got a temperature of 32, and we returned a value of 0 We got a temperature of 100, and we returned a value of 37 We got a temperature of 212, and we returned a value of 100 We're shutting down... D:\data\RPC\examples\onrpc_temp\server\Debug>
Summary • Linux RPC Implementation models SUN ONCRPC functionality • RPC specific programming limited to linking original applications code with rpcgen interface code.