Diferenças

Aqui você vê as diferenças entre duas revisões dessa página.

Link para esta página de comparações

Ambos lados da revisão anterior Revisão anterior
pua:exemplo_de_rpc [2013/09/24 17:34] mazieropua:exemplo_de_rpc [2020/08/18 22:51] (atual) – edição externa 127.0.0.1
Linha 1: Linha 1:
 +====== Exemplo de uso de RPC ======
 +
 +
 +Em RPC, o único vínculo explícito entre o servidor e seus clientes é a especificação da interface do serviço oferecido.  Essa especificação segue um formato relativamente simples. O exemplo a seguir define um serviço composto de duas operações: ADD e SUB:
 +
 +<code c addsub.x>
 +/* addsub.x : definição da interface */
 +
 +#define PROGRAM_NUMBER 12345678
 +#define VERSION_NUMBER 1
 +
 +/* tipo de dado que será passado aos procedimentos remotos */
 +
 +struct operands
 +{
 +        int x;
 +        int y;
 +};
 +
 +/* Definição da interface que será oferecida aos clientes */
 +
 +program ADDSUB_PROG
 +{
 +   version ADDSUB_VERSION
 +   {
 +     int ADD (operands) = 1;
 +     int SUB (operands) = 2;
 +   }
 +   = VERSION_NUMBER;
 +}
 += PROGRAM_NUMBER;
 +</code>
 +
 +Essa definição de interface deve ser compilada pelo utilitário ''rpcgen'', gerando diversos arquivos de código e cabeçalho que serão compilados juntamente com o cliente e o servidor:
 +
 +<code>
 +espec:rpc> rpcgen -C addsub.x
 +espec:rpc> ll
 +total 28
 +-rw-r--r--    1 prof          842 Out 16 21:36 addsub_clnt.c
 +-rw-r--r--    1 prof         1113 Out 16 21:36 addsub.h
 +-rw-r--r--    1 prof         2360 Out 16 21:36 addsub_svc.c
 +-rw-r--r--    1 prof          423 Out 16 21:34 addsub.x
 +-rw-r--r--    1 prof          287 Out 16 21:36 addsub_xdr.c
 +</code>
 +
 +A seguir devem ser escritos o cliente e o servidor que irão se comunicar usando essa especificação. Como o servidor é passivo e só aguarda, processa e responde pedidos, seu código é bastante simples:
 +
 +<code c server.c>
 +/* Arquivo server.c: um servidor RPC simples */
 +#include <stdio.h>
 +#include "addsub.h"
 +
 +/* implementação da função add */
 +int * add_1_svc (operands *argp, struct svc_req *rqstp)
 +{
 +   static int result;
 +
 +   printf ("Recebi chamado: add %d %d\n", argp->x, argp->y);
 +   result = argp->x + argp->y;
 +   return (&result);
 +}
 +
 +/* implementação da função sub */
 +int * sub_1_svc (operands *argp, struct svc_req *rqstp)
 +{
 +   static int result;
 +
 +   printf ("Recebi chamado: sub %d %d\n", argp->x, argp->y);
 +   result = argp->x - argp->y;
 +   return (&result);
 +}
 +</code>
 +
 +O código do cliente é um pouco mais complexo, pois ele precisa obter uma referência do servidor antes de submeter seus pedidos:
 +
 +<code c client.c>
 +/* Arquivo client.c: um cliente RPC simples */
 +
 +#include <stdio.h>
 +#include "addsub.h"
 +
 +/* função que chama a RPC add_1 */
 +int add (CLIENT *clnt, int x, int y)
 +{
 +   operands ops;
 +   int *result;
 +
 +   /* junta os parâmetros em um struct */
 +   ops.x = x;
 +   ops.y = y;
 +
 +   /* chama a função remota */
 +   result = add_1 (&ops,clnt);
 +   if (result == NULL)
 +   {
 +     printf ("Problemas ao chamar a função remota\n");
 +     exit (1);
 +   }
 +
 +   return (*result);
 +}
 +
 +/* função que chama a RPC sub_1 */
 +int sub (CLIENT *clnt, int x, int y)
 +{
 +   operands ops;
 +   int *result;
 +
 +   /* junta os parâmetros em um struct */
 +   ops.x = x;
 +   ops.y = y;
 +
 +   /* chama a função remota */
 +   result = sub_1 (&ops,clnt);
 +   if (result == NULL)
 +   {
 +      printf ("Problemas ao chamar a função remota\n");
 +      exit (1);
 +   }
 +   return (*result);
 +}
 +
 +int main( int argc, char *argv[])
 +{
 +   CLIENT *clnt;
 +   int x,y;
 +
 +   /* verifica se o cliente foi chamado corretamente */
 +   if (argc!=4)
 +   {
 +      fprintf (stderr,"Usage: %s hostname num1 num2\n",argv[0]);
 +      exit (1);
 +   }
 +
 +   /* cria uma struct CLIENT que referencia uma interface RPC */
 +   clnt = clnt_create (argv[1], ADDSUB_PROG, ADDSUB_VERSION, "udp");
 +
 +   /* verifica se a referência foi criada */
 +   if (clnt == (CLIENT *) NULL)
 +   {
 +      clnt_pcreateerror (argv[1]);
 +      exit(1);
 +   }
 +
 +   /* obtém os dois inteiros que serão passados via RPC */
 +   x = atoi (argv[2]);
 +   y = atoi (argv[3]);
 +
 +   /* executa os procedimentos remotos */
 +   printf ("%d + %d = %d\n", x, y, add (clnt,x,y));
 +   printf ("%d - %d = %d\n", x, y, sub (clnt,x,y));
 +
 +   return (0);
 +}
 +</code>
 +
 +Em seguida, cliente e servidor podem ser compilados separadamente, para gerar os executáveis ''client'' e ''server'':
 +
 +<code>
 +$ cc server.c addsub_svc.c  addsub_xdr.c -o server -lnsl
 +$ cc client.c addsub_clnt.c addsub_xdr.c -o client -lnsl
 +$ ll
 +total 60
 +-rw-r--r--    1 prof          842 Out 16 21:36 addsub_clnt.c
 +-rw-r--r--    1 prof         1113 Out 16 21:36 addsub.h
 +-rw-r--r--    1 prof         2360 Out 16 21:36 addsub_svc.c
 +-rw-r--r--    1 prof          423 Out 16 21:34 addsub.x
 +-rw-r--r--    1 prof          287 Out 16 21:36 addsub_xdr.c
 +-rwxr-xr-x    1 prof        13523 Out 16 21:37 client
 +-rw-r--r--    1 prof         1583 Out 16 21:29 client.c
 +-rwxr-xr-x    1 prof        14598 Out 16 21:37 server
 +-rw-r--r--    1 prof          507 Out 16 21:28 server.c
 +</code>
 +
 +O servidor (arquivo ''server'') deve ser lançado antes do cliente (arquivo ''client''), de preferência em uma janela separada.