Читать интересную книгу UNIX: взаимодействие процессов - Уильям Стивенс

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 104 105 106 107 108 109 110 111 112 ... 128

//sunrpc/xdr1/example.c

1  #include "unpipc.h"

2  #include "example.h"

3  int

4  main(int argc, char **argv)

5  {

6   int size;

7   example foo;

8   size = RNDUP(sizeof(foo.a)) + RNDUP(sizeof(foo.b)) +

9    RNDUP(sizeof(foo.c[0])) * MAXC;

10  printf("size = %dn", size);

11  exit(0);

12 }

8-9 Макрос RNDUP определен в файле <rpc/xdr.h>. Он округляет аргумент к ближайшему кратному BYTES_PER_XDR_UNIT (4). Для массива фиксированного размера вычисляется размер каждого элемента, который затем умножается на количество элементов.

Проблема возникает в случае использования типов данных переменной длины. Если мы объявим stringd<10>, максимальный размер будет RNDUP(sizeof( int)) (для длины) плюс RNDUP(sizeof(char)*10) (для символов строки). Но мы не можем вычислить размер буфера, если максимальный размер не указан в объявлении переменной (например, float e<>). Лучше всего в этом случае выделять буфер с запасом, а потом проверять, не возвращают ли подпрограммы XDR ошибку (упражнение 16.5).

Пример: необязательные данные

Существуют три способа задания необязательных данных в файле XDR, примеры для всех приведены в листинге 16.17.

Листинг 16.17. Файл спецификации XDR, иллюстрирующий способы задания необязательных данных

//sunrpc/xdr1/opt1.x

1  union optlong switch (bool flag) {

2  case TRUE:

3   long val;

4  case FALSE:

5   void;

6  };

7  struct args {

8   optlong arg1; /* объединение с булевским дискриминантом */

9   long arg2<1>; /* массив переменной длины с одним элементом */

10  long *arg3; /* указатель */

11 };

Объявление объединения с булевским дискриминантом

1-8 Мы определяем объединение с ветвями FALSE и TRUE и структуру этого типа. Если флаг дискриминанта TRUE, за ним следует значение типа long; в противном случае за ним ничего не следует. После кодирования библиотекой XDR это объединение будет закодировано как:

■ 4 байта флага со значением 1 (TRUE) и 4 байта целочисленного значения либо

■ 4 байта флага со значением 0 (FALSE).

Объявление массива переменной длины

9 Если мы указываем массив переменной длины с одним возможным элементом, он будет передан как:

■ 4 байта со значением 1 и 4 байта значения либо

■ 4 байта со значением 0.

Объявление указателя XDR

10 Новый способ определения необязательных данных заключается в объявлении указателя. Он будет закодирован как:

■ 4 байта со значением 1 и 4 байта значения либо

■ 4 байта со значением 0

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

Важная деталь реализации, благодаря которой оба варианта дают одинаковый результат при кодировании, заключается в том, что значение TRUE равно 1, что совпадает с длиной массива переменной длины, когда в нем есть один элемент.

В листинге 16.18 приведен текст заголовочного файла, созданного программой rpcgen для данного файла спецификации.

Листинг 16.18. Заголовочный файл, получившийся в результате обработки листинга 16.17

//sunrpc/xdr1/opt1.h

7  struct optlong {

8   bool_t flag;

9   union {

10  long val;

11  } optlong_u;

12 };

13 typedef struct optlong optlong;

14 struct args {

15  optlong arg1;

16  struct {

17   u_int arg2_len;

18   long *arg2_val;

19  } arg2;

20  long *arg3;

21 };

22 typedef struct args args;

14-21 Хотя все три аргумента кодируются одинаково, способы присваивания и получения их значений в языке С различны.

В листинге 16.19 приведен текст простой пpoгрaммы, устанавливающей значения всех трех аргументов так, что ни одно из полей long не кодируется.

Листинг 16.19. Ни одно из значений не будет закодировано

//sunrpc/xdr1/opt1z.с

1  #include "unpipc.h"

2  #include "opt1.h"

3  int

4  main(int argc, char **argv)

5  {

6   int i;

7   XDR xhandle;

8   char *buff;

9   long *lptr;

10  args out;

11  size_t size;

12  out.arg1.flag = FALSE;

13  out.arg2.arg2_len = 0;

14  out.arg3 = NULL;

15  buff = Malloc(BUFFSIZE); /* Адрес должен быть кратен четырем */

16  xdrmem_create(&xhandle, buff, BUFFSIZE, XOR_ENCODE);

17  if (xdr_args(&xhandle, &out) != TRUE)

18   err_quit("xdr_args error");

19  size = xdr_getpos(&xhandle);

20  lptr = (long*)buff;

21  for (i = 0; i < size; i += 4)

22   printf("%ldn", (long) ntohl(*lptr++));

23  exit(0);

24 }

Присваивание значений

12-14 Дискриминанту объединения присваивается значение FALSE, длина массива переменной длины устанавливается в 0, а указатель делается нулевым (NULL).

Выделение буфера и кодирование

15-19 Мы выделяем буфер и кодируем структуру out в поток XDR. 

Вывод содержимого буфера XDR

20-22 Мы выводим содержимое буфера XDR по 4 байта, используя функцию ntohl (host-to-network long integer) для преобразования из порядка XDR big-endian в байтовый порядок узла. В результате получается именно то, что должно было быть помещено в буфер библиотекой XDR времени выполнения:

solaris % opt1z

0

0

0

Как мы и предполагали, каждому аргументу отводится 4 байта со значением О, указывающим на то, что за ним не следует никаких данных.

В листинге 16.20 приведена измененная версия программы, которая присваивает значения всем трем аргументам, кодирует их в поток XDR и выводит его содержимое.

Листинг 16.20. Присваивание значений аргументам из листинга 16.17

//sunrpc/xdr1/opt1.c

1  #include "unpipc.h"

2  #include "opt1.h"

3  int

4  main(int argc, char **argv)

5  {

6   int i;

7   XOR xhandle;

8   char *buff;

9   long lval2, lval3, *lptr;

10  args out;

11  size_t size;

12  out.arg1.flag = TRUE;

13  out.arg1.optlong_u.val = 5;

14  lval2 = 9876;

15  out.arg2.arg2_len = 1;

16  out.arg2.arg2_val = &lval2;

17  lval3 = 123;

18  out.arg3 = &lval3;

19  buff = Malloc(BUFFSIZE); /* адрес должен быть кратен 4 */

20  xdrmem_create(&xhandle, buff, BUFFSIZE, XDR_ENCODE);

21  if (xdr_args(&xhandle, &out) != TRUE)

22   err_quit("xdr_args error");

23  size = xdr_getpos(&xhandle);

24  lptr = (long *) buff;

25  for (i = 0; i < size; i += 4)

26   printf("%ldn", (long) ntohl(*lptr++));

27  exit(0);

28 }

Присваивание значений

12-18 Для присваивания значения объединению мы устанавливаем дискриминант в TRUE, а затем присваиваем значение полю long. Длину массива мы также сначала устанавливаем в 1. Указатель мы устанавливаем на соответствующее значение в памяти.

При запуске этой программы мы получим ожидаемые шесть 4-байтовых значений:

solaris % opt1

1 значение дискриминанта TRUE

5

1 длина массива переменной длины

9876

1 флаг для ненулевого указателя

123

Пример: обработка связного списка

Если осуществима передача необязательных данных, мы можем расширить возможности указателей в XDR и использовать их для кодирования и декодирования связных списков, содержащих произвольное количество элементов. В нашем примере используется связный список пар имя-значение. Соответствующий файл спецификации XDR приведен в листинге 16.21.

Листинг 16.21. Спецификация XDR для связного списка пар имя-значение

//sunrpc/xdr1/opt2.x

1 struct mylist {

2  string name<>;

3  long value;

4  mylist *next;

5 };

6 struct args {

7  mylist *list;

8 };

1-5 Структура mylist содержит одну пару имя-значение и указатель на следующую структуру такого типа. Указатель в последней структуре списка будет нулевым.

В листинге 16.22 приведен текст заголовочного файла, созданного программой rpcgen из файла opt2.х.

Листинг 16.22. Заголовочный файл, созданный программой rpcgen

//sunrpc/xdr1/opt2.h

7  struct mylist {

8   char *name;

9   long value;

10  struct mylist *next;

1 ... 104 105 106 107 108 109 110 111 112 ... 128
На этом сайте Вы можете читать книги онлайн бесплатно русская версия UNIX: взаимодействие процессов - Уильям Стивенс.

Оставить комментарий