📄 rpc.prog.ms
字号:
bool = TRUE; else bool = FALSE; if (!svc_sendreply(transp, xdr_bool, &bool)) { fprintf(stderr, "can't reply to RPC call\en"); return (1); } return;}.DE.KE.LPThe relevant routine is.I svc_getargs()which takes an.I SVCXPRThandle, the XDR routine,and a pointer to where the input is to be placed as arguments..NH 2\&Memory Allocation with XDR.IX "memory allocation with XDR".IX XDR "memory allocation".LPXDR routines not only do input and output,they also do memory allocation.This is why the second parameter of.I xdr_array()is a pointer to an array, rather than the array itself.If it is.I NULL ,then.I xdr_array()allocates space for the array and returns a pointer to it,putting the size of the array in the third argument.As an example, consider the following XDR routine.I xdr_chararr1()which deals with a fixed array of bytes with length.I SIZE ..ie t .DS.el .DS L.ft CWxdr_chararr1(xdrsp, chararr) XDR *xdrsp; char chararr[];{ char *p; int len; p = chararr; len = SIZE; return (xdr_bytes(xdrsp, &p, &len, SIZE));}.DEIf space has already been allocated in.I chararr ,it can be called from a server like this:.ie t .DS.el .DS L.ft CWchar chararr[SIZE];svc_getargs(transp, xdr_chararr1, chararr);.DEIf you want XDR to do the allocation,you would have to rewrite this routine in the following way:.ie t .DS.el .DS L.ft CWxdr_chararr2(xdrsp, chararrp) XDR *xdrsp; char **chararrp;{ int len; len = SIZE; return (xdr_bytes(xdrsp, charrarrp, &len, SIZE));}.DEThen the RPC call might look like this:.ie t .DS.el .DS L.ft CWchar *arrptr;arrptr = NULL;svc_getargs(transp, xdr_chararr2, &arrptr);.ft I/* * Use the result here */.ft CWsvc_freeargs(transp, xdr_chararr2, &arrptr);.DENote that, after being used, the character array can be freed with.I svc_freeargs().I svc_freeargs() will not attempt to free any memory if the variable indicating it is NULL. For example, in the the routine .I xdr_finalexample (),given earlier, if.I finalp->string was NULL, then it would not be freed. The same is true for .I finalp->simplep ..LPTo summarize, each XDR routine is responsiblefor serializing, deserializing, and freeing memory.When an XDR routine is called from.I callrpc()the serializing part is used.When called from.I svc_getargs()the deserializer is used.And when called from.I svc_freeargs()the memory deallocator is used. When building simple examples like thosein this section, a user doesn't have to worry about the three modes. See the.I "External Data Representation: Sun Technical Notes"for examples of more sophisticated XDR routines that determine which of the three modes they are in and adjust their behavior accordingly..KS.NH 2\&The Calling Side.IX RPC "calling side".LPWhen you use.I callrpc()you have no control over the RPC deliverymechanism or the socket used to transport the data.To illustrate the layer of RPC that lets you adjust theseparameters, consider the following code to call the.I nusersservice:.ie t .DS.el .DS L.ft CW.vs 11#include <stdio.h>#include <rpc/rpc.h>#include <utmp.h>#include <rpcsvc/rusers.h>#include <sys/socket.h>#include <sys/time.h>#include <netdb.h>main(argc, argv) int argc; char **argv;{ struct hostent *hp; struct timeval pertry_timeout, total_timeout; struct sockaddr_in server_addr; int sock = RPC_ANYSOCK; register CLIENT *client; enum clnt_stat clnt_stat; unsigned long nusers; if (argc != 2) { fprintf(stderr, "usage: nusers hostname\en"); exit(-1); } if ((hp = gethostbyname(argv[1])) == NULL) { fprintf(stderr, "can't get addr for %s\en",argv[1]); exit(-1); } pertry_timeout.tv_sec = 3; pertry_timeout.tv_usec = 0; bcopy(hp->h_addr, (caddr_t)&server_addr.sin_addr, hp->h_length); server_addr.sin_family = AF_INET; server_addr.sin_port = 0; if ((client = clntudp_create(&server_addr, RUSERSPROG, RUSERSVERS, pertry_timeout, &sock)) == NULL) { clnt_pcreateerror("clntudp_create"); exit(-1); } total_timeout.tv_sec = 20; total_timeout.tv_usec = 0; clnt_stat = clnt_call(client, RUSERSPROC_NUM, xdr_void, 0, xdr_u_long, &nusers, total_timeout); if (clnt_stat != RPC_SUCCESS) { clnt_perror(client, "rpc"); exit(-1); } clnt_destroy(client); close(sock); exit(0);}.vs.DE.KEThe low-level version of.I callrpc()is.I clnt_call()which takes a.I CLIENTpointer rather than a host name. The parameters to.I clnt_call() are a.I CLIENT pointer, the procedure number,the XDR routine for serializing the argument,a pointer to the argument,the XDR routine for deserializing the return value,a pointer to where the return value will be placed,and the time in seconds to wait for a reply..LPThe.I CLIENT pointer is encoded with the transport mechanism..I callrpc()uses UDP, thus it calls.I clntudp_create() to get a.I CLIENT pointer. To get TCP (Transmission Control Protocol), you would use.I clnttcp_create() ..LPThe parameters to.I clntudp_create() are the server address, the program number, the version number,a timeout value (between tries), and a pointer to a socket.The final argument to.I clnt_call() is the total time to wait for a response.Thus, the number of tries is the.I clnt_call() timeout divided by the.I clntudp_create() timeout..LPNote that the.I clnt_destroy()callalways deallocates the space associated with the.I CLIENT handle. It closes the socket associated with the.I CLIENT handle, however, only if the RPC library opened it. It thesocket was opened by the user, it stays open. This makes itpossible, in cases where there are multiple client handlesusing the same socket, to destroy one handle without closingthe socket that other handles are using..LPTo make a stream connection, the call to.I clntudp_create() is replaced with a call to.I clnttcp_create() ..DS.ft CWclnttcp_create(&server_addr, prognum, versnum, &sock, inputsize, outputsize);.DEThere is no timeout argument; instead, the receive and send buffersizes must be specified. When the.I clnttcp_create() call is made, a TCP connection is established.All RPC calls using that.I CLIENT handle would use this connection.The server side of an RPC call using TCP has.I svcudp_create()replaced by.I svctcp_create() ..DS.ft CWtransp = svctcp_create(RPC_ANYSOCK, 0, 0);.DEThe last two arguments to .I svctcp_create() are send and receive sizes respectively. If `0' is specified for either of these, the system chooses a reasonable default..KS.NH 1\&Other RPC Features.IX "RPC" "miscellaneous features".IX "miscellaneous RPC features".LPThis section discusses some other aspects of RPCthat are occasionally useful..NH 2\&Select on the Server Side.IX RPC select() RPC \fIselect()\fP.IX select() "" \fIselect()\fP "on the server side".LPSuppose a process is processing RPC requestswhile performing some other activity.If the other activity involves periodically updating a data structure,the process can set an alarm signal before calling.I svc_run()But if the other activityinvolves waiting on a a file descriptor, the.I svc_run()call won't work.The code for.I svc_run()is as follows:.ie t .DS.el .DS L.ft CW.vs 11voidsvc_run(){ fd_set readfds; int dtbsz = getdtablesize(); for (;;) { readfds = svc_fds; switch (select(dtbsz, &readfds, NULL,NULL,NULL)) { case -1: if (errno == EINTR) continue; perror("select"); return; case 0: break; default: svc_getreqset(&readfds); } }}.vs.DE.KE.LPYou can bypass.I svc_run()and call.I svc_getreqset()yourself.All you need to know are the file descriptorsof the socket(s) associated with the programs you are waiting on.Thus you can have your own.I select() .IX select() "" \fIselect()\fPthat waits on both the RPC socket,and your own descriptors. Note that.I svc_fds() is a bit mask of all the file descriptors that RPC is using for services. It can change everytime that.I anyRPC library routine is called, because descriptors are constantly being opened and closed, for example for TCP connections..NH 2\&Broadcast RPC.IX "broadcast RPC".IX RPC "broadcast".LPThe.I portmapperis a daemon that converts RPC program numbersinto DARPA protocol port numbers; see the.I portmap man page. You can't do broadcast RPC without the portmapper.Here are the main differences betweenbroadcast RPC and normal RPC calls:.IP 1.Normal RPC expects one answer, whereasbroadcast RPC expects many answers(one or more answer from each responding machine)..IP 2.Broadcast RPC can only be supported by packet-oriented (connectionless)transport protocols like UPD/IP..IP 3.The implementation of broadcast RPCtreats all unsuccessful responses as garbage by filtering them out.Thus, if there is a version mismatch between thebroadcaster and a remote service,the user of broadcast RPC never knows..IP 4.All broadcast messages are sent to the portmap port.Thus, only services that register themselves with their portmapperare accessible via the broadcast RPC mechanism..IP 5.Broadcast requests are limited in size to the MTU (Maximum TransferUnit) of the local network. For Ethernet, the MTU is 1500 bytes..KS.NH 3\&Broadcast RPC Synopsis.IX "broadcast RPC" synopsis.IX "RPC" "broadcast synopsis".ie t .DS.el .DS L.ft CW#include <rpc/pmap_clnt.h> . . .enum clnt_stat clnt_stat; . . .clnt_stat = clnt_broadcast(prognum, versnum, procnum, inproc, in, outproc, out, eachresult) u_long prognum; /* \fIprogram number\fP */ u_long versnum; /* \fIversion number\fP */ u_long procnum; /* \fIprocedure number\fP */ xdrproc_t inproc; /* \fIxdr routine for args\fP */ caddr_t in; /* \fIpointer to args\fP */ xdrproc_t outproc; /* \fIxdr routine for results\fP */ caddr_t out; /* \fIpointer to results\fP */ bool_t (*eachresult)();/* \fIcall with each result gotten\fP */.DE.KEThe procedure.I eachresult()is called each time a valid result is obtained.It returns a boolean that indicateswhether or not the user wants more responses..ie t .DS.el .DS L.ft CWbool_t done; . . . done = eachresult(resultsp, raddr) caddr_t resultsp; struct sockaddr_in *raddr; /* \fIAddr of responding machine\fP */.DEIf.I doneis.I TRUE ,then broadcasting stops and.I clnt_broadcast()returns successfully.Otherwise, the routine waits for another response.The request is rebroadcastafter a few seconds of waiting.If no responses come back,the routine returns with.I RPC_TIMEDOUT ..NH 2\&Batching.IX "batching".IX RPC "batching".LPThe RPC architecture is designed so that clients send a call message,and wait for servers to reply that the call succeeded.This implies that clients do not computewhile servers are processing a call.This is inefficient if the client does not want or needan acknowledgement for every message sent.It is possible for clients to continue computingwhile waiting for a response,using RPC batch facilities..LPRPC messages can be placed in a \*Qpipeline\*U of callsto a desired server; this is called batching.Batching assumes that:1) each RPC call in the pipeline requires no response from the server,and the server does not send a response message; and2) the pipeline of calls is transported on a reliablebyte stream transport such as TCP/IP.Since the server does not respond to every call,the client can generate new calls in parallelwith the server executing previous calls.Furthermore, the TCP/IP implementation can buffer upmany call messages, and send them to the server in one.I write()system call. This overlapped executiongreatly decreases the interprocess communication overhead ofthe client and server processes,and the total elapsed time of a series of calls..LPSince the batched calls are buffered,the client should eventually do a nonbatched callin order to flush the pipeline..LPA contrived example of batching follows.Assume a string rendering service (like a window system)has two similar calls: one renders a string and returns void results,while the other renders a string and remains silent.The service (using the TCP/IP transport) may look like:.ie t .DS.el .DS L.ft CW#include <stdio.h>#include <rpc/rpc.h>#include <suntool/windows.h>void windowdispatch();main(){ SVCXPRT *transp; transp = svctcp_create(RPC_ANYSOCK, 0, 0); if (transp == NULL){ fprintf(stderr, "can't create an RPC server\en"); exit(1); } pmap_unset(WINDOWPROG, WINDOWVERS); if (!svc_register(transp, WINDOWPROG, WINDOWVERS, windowdispatch, IPPROTO_TCP)) { fprintf(stderr, "can't register WINDOW service\en"); exit(1); } svc_run(); /* \fINever returns\fP */ fprintf(stderr, "should never reach this point\en");}voidwindowdispatch(rqstp, transp) struct svc_req *rqstp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -