TCP 上的 rcp 进程示例

本节说明 TCP 示例上的 rpc 进程。

以下是使用 rcp 进程的示例。 此示例包含 eXternal 数据表示 (XDR) 过程,该过程在序列化上的行为与在反序列化上的行为不同。 远程过程调用 (RPC) snd 调用的发起方接受其标准输入,并将其发送到服务器上的 rcv 进程,该进程将数据打印到标准输出。 snd 调用使用 Transmission Control Protocol (TCP)。

例程如下所示:

/*
 * The xdr routine:
 *   on decode, read from wire, write onto fp
 *   on encode, read from fp, write onto wire
 */
#include <stdio.h>
#include <rpc/rpc.h>

xdr_rcp(xdrs, fp)
     XDR *xdrs;
     FILE *fp;

{
     unsigned long size;
     char buf[BUFSIZ], *p;
     if (xdrs->x_op == XDR_FREE)     /* nothing to free */
          return 1;
     while (1) {
          if (xdrs->x_op == XDR_ENCODE) {
               if ((size = fread(buf, sizeof(char), BUFSIZ,
                    fp)) == 0 && ferror(fp)) {
                         fprintf(stderr, "can't fread\n");
                         return (1);
               }
          }
          p = buf;
          if (!xdr_bytes(xdrs, &p, &size, BUFSIZ))
               return 0;
          if (size == 0)
               return 1;
          if (xdrs->x_op == XDR_DECODE) {
               if (fwrite(buf, sizeof(char),size,fp) != size) {
                    fprintf(stderr, "can't fwrite\n");
                    return (1);
               }
          }
     }
}

/*
 * The sender routines
 */
#include <stdio.h>
#include <netdb.h>
#include <rpc/rpc.h>
#include <sys/socket.h>
#include <sys/time.h>

main(argc, argv)
     int argc;
     char **argv;

{
     int xdr_rcp();
     int err;
     if (argc < 2) {
          fprintf(stderr, "usage: %s servername\n", argv[0]);
          exit(-1);
     }
     if ((err = callrpctcp(argv[1], RCPPROG, RCPPROC,
       RCPVERS, xdr_rcp, stdin, xdr_void, 0) != 0)) {
          clnt_perrno(err);
          fprintf(stderr, "can't make RPC call\n");
          exit(1);
     }
     exit(0);
}

callrpctcp(host, prognum, procnum, versnum, inproc, in,
          outproc, out)
     char *host, *in, *out;
     xdrproc_t inproc, outproc;

{
     struct sockaddr_in server_addr;
     int socket = RPC_ANYSOCK;
     enum clnt_stat clnt_stat;
     struct hostent *hp;
     register CLIENT *client;
     struct timeval total_timeout;

     if ((hp = gethostbyname(host)) == NULL) {
          fprintf(stderr, "can't get addr for '%s'\n", host);
          return (-1);
     }
     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 = clnttcp_create(&server_addr, prognum,
       versnum, &socket, BUFSIZ, BUFSIZ)) == NULL) {
          perror("rpctcp_create");
          return (-1);
     }
     total_timeout.tv_sec = 20;
     total_timeout.tv_usec = 0;
     clnt_stat = clnt_call(client, procnum,
          inproc, in, outproc, out, total_timeout);
     clnt_destroy(client);
     return (int)clnt_stat;
}

/*
 * The receiving routines
 */
#include <stdio.h>
#include <rpc/rpc.h>

main()
{
     register SVCXPRT *transp;
     int rcp_service(), xdr_rcp(); 

     if ((transp = svctcp_create(RPC_ANYSOCK,
       BUFSIZ, BUFSIZ)) == NULL) {
          fprintf("svctcp_create: error\n");
          exit(1);
     }
     pmap_unset(RCPPROG, RCPVERS);
     if (!svc_register(transp,
       RCPPROG, RCPVERS, rcp_service, IPPROTO_TCP)) {
          fprintf(stderr, "svc_register: error\n");
          exit(1);
     }
     svc_run();     /* never returns */
     fprintf(stderr, "svc_run should never return\n");
}

rcp_service(rqstp, transp)
     register struct svc_req *rqstp;
     register SVCXPRT *transp;

{
     switch (rqstp->rq_proc) {
     case NULLPROC:
          if (svc_sendreply(transp, xdr_void, 0) == 0) {
               fprintf(stderr, "err: rcp_service");
               return (1);
           }
           return;
     case RCPPROC_FP:
          if (!svc_getargs(transp, xdr_rcp, stdout)) {
               svcerr_decode(transp);
               return;
           }
           if (!svc_sendreply(transp, xdr_void, 0)) {
                fprintf(stderr, "can't reply\n");
                return;
          }
          return (0);
     default:
          svcerr_noproc(transp);
          return;
     }
}