next up previous contents
Next: Передача сложных структур данных Up: Удаленный вызов процедур Previous: Компиляция протоколов и низкоуровневое   Contents

Преобразование локальных процедур в удаленные

Пусть приложение работает на отдельном компьютере, и его необходимо преобразовать, чтобы использовать в "распределенной" сети. Ниже показано пошаговое преобразование программы, которая выводит сообщения на терминал.

Однопроцессная версия printmesg.c:

/* printmsg.c: выводит сообщение на терминал */

#include <stdio.h>

main(int argc, char *argv[])

{

  char *message;

  if (argc != 2) {

     fprintf(stderr, "usage: %s <message>\n",argv[0]);

     exit(1);

  }

  message = argv[1];

  if (!printmessage(message)) {

     fprintf(stderr,"%s: невозможно вывести сообщение\n",

         argv[0]); exit(1);

  }

  printf("Сообщение выведено!\n");

  exit(0);

}

/* Вывод сообщения на терминал.

* Возвращает логическое значение, показывающее

* выведено ли сообщение. */

printmessage(char *msg)  {

  FILE *f;

  f = fopen("/dev/console", "w");

  if (f == (FILE *)NULL)  return (0);

  fprintf(f, "%s\n", msg);

  fclose(f);

  return(1);

}

Если функцию printmessage() превратить в удаленную процедуру, ее можно вызывать на любой машине сети.

Сначала необходимо определить типы данных всех аргументов вызова процедуры и результата. Аргумент вызова printmessage() представляет собой строку, а результат - целое число. Теперь можно написать спецификацию протокола на языке RPC, который будет описывать удаленную версию printmessage(). Исходный код RPC для данной спецификации:

/* msg.x: Удаленный протокол вывода сообщения */

program MESSAGEPROG {

  version PRINTMESSAGEVERS {

    int PRINTMESSAGE(string) = 1;

  } = 1;

} = 0x20000001;

Удаленные процедуры всегда объявляются как часть удаленных программ. Код выше описывает полную удаленную программу, которая содержит единственную процедуру PRINTMESSAGE.

В этом примере PRINTMESSAGE - это процедура номер 1 в версии 1 удаленной программы MESSAGEPROG с номером программы 0x20000001.

Номера версии увеличиваются, если в удаленной программе изменяются функциональные возможности. При этом могут быть заменены существующие процедуры или добавлены новые. Может быть определена более чем одна версия удаленной программы, а также каждая версия может иметь более одной определенной процедуры.

Необходимо разработать еще две дополнительные программы. Одной из них является сама удаленная процедура. Версия printmsg.c для RPC:

/*

* msg_proc.c: реализация удаленной процедуры 

* "printmessage" */

#include <stdio.h>

#include "msg.h" /* msg.h сгенерированный rpcgen */

 

int * printmessage_1(char **msg, struct svc_req *req) {

  static int result; /* должен быть static! */

  FILE *f;

  f = fopen("/dev/console", "w");

  if (f == (FILE *)NULL) {

     result = 0;

     return (&result);

  }

  fprintf(f, "%s\n", *msg);

  fclose(f);

  result = 1;

  return (&result);

}

При этом определение удаленной процедуры printmessage_1 отличается от локальной процедуры printmessage в следующих моментах:

Пример клиентской программы, которая вызывает процедуру:

/*

* rprintmsg.c: удаленная версия "printmsg.c"

*/

#include <stdio.h>

#include "msg.h" /* msg.h сгенерирован rpcgen */

 

main(int argc, char **argv)

{

  CLIENT *clnt;

  int *result;

  char *server;

  char *message;

  if (argc != 3) {

     fprintf(stderr, "usage: %s host

     message\n", argv[0]);

     exit(1);

  }

  server = argv[1];

  message = argv[2];

 

  /*

  * Создает клиентский "обрабочик", используемый

  * для вызова MESSAGEPROG на сервере

  */

  clnt = clnt_create(server, MESSAGEPROG,

       PRINTMESSAGEVERS, "visible");

  if (clnt == (CLIENT *)NULL) {

    /*

    * Невозможно установить соединение с сервером.

    */

    clnt_pcreateerror(server);

    exit(1);

  }

 

  /*

  * Вызов удаленной процедуры

  * "printmessage" на сервере

  */

  result = printmessage_1(&message, clnt);

  if (result == (int *)NULL) {

     /*

     * Ошибка при вызове сервера

     */

     clnt_perror(clnt, server);

     exit(1);

  }

 

  /* Успешный вызов удаленной процедуры.

  */

  if (*result == 0) {

     /*

     * Сервер не может вывести сообщение.

     */

     fprintf(stderr, "%s: невозможно вывести

           сообщение\n", argv[0]);

     exit(1);

  }

 

  /* Сообщение выведено на терминал сервера

  */

  printf("Сообщение доставлено %s\n", server);

  clnt_destroy( clnt );

  exit(0);

}

Следует отметить следующие особенности клиентской программы вызова printmsg.c:

Вызов удаленной процедуры может завершиться неудачно по двум причинам: либо произойдет ошибка в механизме RPC, либо ошибка в выполнении удаленной процедуры. В первом случае удаленная процедура printmessage_1 возвращает NULL. Во втором случае сообщение об ошибке зависит от приложения. Здесь ошибка возвращается через *result.

Для компиляции примера удаленного rprintmsg:

  1. Откомпилируйте протокол, определенный в msg.x: rpcgen msg.x. При этом должны быть созданы заголовочный файл (msg.h), клиентская часть (msg_clnt.c), и серверная часть (msg_svc.c).

  2. Откомпилируйте исполняемый файл клиента:

    cc rprintmsg.c msg_clnt.c -o rprintmsg -lnsl 
  3. Откомпилируйте исполняемый файл сервера:
    cc msg_proc.c msg_svc.c -o msg_server -lnsl
Объектные файлы C должны быть скомпонованы с библиотекой libnsl, которая содержит все сетевые функции, включая версии для RPC и XDR.

В этом примере не было создано никаких процедур XDR, потому что приложение использует только основные типы, которые включены в libnsl. Теперь нужно рассмотреть, что создано rpcgen на основе входного файла msg.x:

После того, как программа сервера создана, ее можно установить на удаленной машине и запустить. (Если машины гомогенны, двоичные файлы сервера можно просто скопировать. Если они различны, исходные файлы сервера должны быть компилироваться на удаленной машине отдельно.)


next up previous contents
Next: Передача сложных структур данных Up: Удаленный вызов процедур Previous: Компиляция протоколов и низкоуровневое   Contents
2004-06-22