Книга: UNIX: взаимодействие процессов

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

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

Существуют три способа задания необязательных данных в файле 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

Оглавление книги


Генерация: 1.287. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз